# Go Backend Spacing Primitives Design

**Date:** 2026-05-10

**Goal**

Add fixed-size spacing primitives to the Go backend UI library so templates can insert consistent horizontal and vertical gaps between other components without relying on ad hoc inline markup.

**Chosen Approach**

Introduce two small presentational primitives:

- `SpaceX` for horizontal spacing
- `SpaceY` for vertical spacing

Both primitives will use the same named spacing scale:

- `xs`
- `sm`
- `md`
- `lg`
- `xl`

This keeps call sites explicit, matches the primitive-oriented structure of the Go UI library, and avoids introducing a child-owning layout abstraction such as `Stack` for this slice.

**Scope**

- Add shared spacing step tokens for UI primitives.
- Add `SpaceX` and `SpaceY` templ components.
- Add stylesheet classes for all supported spacing steps.
- Add catalog examples and a dedicated catalog page for spacing.
- Add direct UI tests and catalog coverage tests.

**Out Of Scope**

- Flexible or grow-to-fill spacers
- Stack or layout wrapper primitives
- Responsive spacing props
- Margin utility generation
- Replacing existing manual spacing usage across the app

**API**

Add:

- `type SpacingStep string`

Supported values:

- `SpacingStepXS`
- `SpacingStepSM`
- `SpacingStepMD`
- `SpacingStepLG`
- `SpacingStepXL`

Add a shared prop shape:

- `type SpaceProps struct { Size SpacingStep }`

Add two primitives:

- `SpaceX(SpaceProps)`
- `SpaceY(SpaceProps)`

Default behavior:

- missing or unknown `Size` normalizes to `SpacingStepMD`

**Rendering Contract**

`SpaceX`:

- renders a presentational `span`
- includes `aria-hidden="true"`
- applies a fixed-width class such as `ui-space-x-md`
- uses `display: inline-block`
- uses `flex-shrink: 0`

`SpaceY`:

- renders a presentational `div`
- includes `aria-hidden="true"`
- applies a fixed-height class such as `ui-space-y-md`

These primitives are empty elements. They do not accept children and do not carry semantic meaning.

**CSS Contract**

Add classes for each step:

- `.ui-space-x-xs` through `.ui-space-x-xl`
- `.ui-space-y-xs` through `.ui-space-y-xl`

Class responsibilities:

- horizontal classes set width only
- vertical classes set height only

Base element behavior should come from the rendered element plus a small shared class contract, not from inline styles.

Recommended scale for this slice:

- `xs`: `0.25rem`
- `sm`: `0.5rem`
- `md`: `0.75rem`
- `lg`: `1rem`
- `xl`: `1.5rem`

This is intentionally small and practical for the current design system. If the library later adopts a broader token system, these values can be remapped behind the same API.

**Normalization And Helpers**

Follow the existing UI pattern of centralizing normalization logic:

- add a `normalizedSpacingStep` helper
- add `spaceXClass` and `spaceYClass` helpers

This keeps templ files simple and makes invalid values deterministic.

**Catalog**

Add a `spacing` catalog page with examples for:

- horizontal spacing between two buttons using `SpaceX`
- vertical spacing between stacked content blocks using `SpaceY`

The examples should render the real primitives rather than static HTML snippets.

**Testing**

Add UI tests that verify:

- `SpaceX` defaults to `md`
- `SpaceY` defaults to `md`
- explicit step selection renders the expected class
- spacers render `aria-hidden="true"`

Add stylesheet coverage checks for:

- `.ui-space-x-md`
- `.ui-space-y-md`

Add catalog tests that verify:

- the `spacing` page exists
- the first spacing example renders real spacer markup

**Implementation Notes**

Files expected for this slice:

- `go-backend/internal/web/ui/space.templ`
- `go-backend/internal/web/ui/space_templ.go`
- updates to `go-backend/internal/web/ui/variants.go` or a nearby helper file for spacing normalization
- updates to `go-backend/internal/web/ui/catalog/examples.go`
- updates to `go-backend/internal/web/ui/catalog/pages.go`
- updates to `go-backend/internal/web/ui/ui_test.go`
- updates to `go-backend/internal/web/ui/catalog/catalog_test.go`
- updates to `go-backend/static/styles.css`

No application call sites need to change as part of this slice. The deliverable is the primitive itself plus documentation and tests.

**Open Decisions Resolved**

- API shape: separate `SpaceX` and `SpaceY`
- sizing model: named spacing steps
- behavior: fixed width and fixed height only
- fallback behavior: default invalid or empty size to `md`

**Success Criteria**

This work is complete when:

- the UI library exposes `SpaceX` and `SpaceY`
- both components render stable classes from the shared spacing scale
- the spacing catalog page documents horizontal and vertical usage
- tests cover primitive markup and catalog registration
- the existing Go backend web UI tests remain green
