Skip to content

Fix docs demos losing Panda's margins to Starlight's reset#111

Merged
czarandy merged 1 commit into
mainfrom
worktree-fix-docs-textinput-status-position
Jul 11, 2026
Merged

Fix docs demos losing Panda's margins to Starlight's reset#111
czarandy merged 1 commit into
mainfrom
worktree-fix-docs-textinput-status-position

Conversation

@czarandy

Copy link
Copy Markdown
Owner

The bug

On the docs site, TextInput's status message sits 4px too low and detaches from the input it belongs to. The same story in Storybook is correct — so this is docs-site-specific, not a component bug.

Docs (before) Storybook (correct)
status message drops 4px, gap under the input message tucked under the input

Cause

Both Panda and Starlight ship layered CSS, and a cascade layer's position is fixed the first time its name is seen — so the docs pages were ordering the two by accident. Panda's layers register first (from panda.css), which puts every starlight.* layer above every Panda one:

reset, base, tokens, recipes, utilities,        ← Panda
starlight.base, starlight.reset, ...            ← Starlight, registered later → wins

Starlight's @layer starlight.reset sets * { margin: 0 }, which therefore beats Panda's margin utilities inside the live demos. On TextInput that silently drops the mt: '-1' in Field.recipe.ts that tucks a status message under its control.

This was never specific to TextInput — it flattened every Panda margin utility in every demo. TextInput is just where it's visible.

Fix

Order the layers explicitly, in site/src/styles/layers.css (loaded first, since a statement only decides the order if it's registered before the sheets it names).

The old astro.config.ts comment warned against an @layer statement, and it was right about the naive one: promoting Panda's layers wholesale puts its preflight above Starlight's prose and unstyles the docs. So this splits Panda's layers around Starlight's instead:

  • reset, base, tokens stay below — Panda's global layers, so Starlight keeps the last word over its own chrome and prose.
  • recipes, utilities go above — every rule in them is selected by a silver-* class, which only the demo components and the site's own islands carry, so they can't reach Starlight's markup but do beat its reset.

Verification

Measured in a headless browser against the built site (not just dev), comparing computed styles to the same Storybook story:

before after Storybook
margin-top 0px -4px -4px
overlap with input 0px 4px 4px

Padding, font size, and line-height already matched and are unchanged. Screenshotted the prose-heavy pages (Getting started, Theming) and a component page to confirm the thing the old comment warned about: Starlight's headings, prose spacing, sidebar, and code blocks are all untouched.

Tests

site/src/styles/layer-order.test.ts pins the properties that make this work, each of which could otherwise regress silently (the demos would just quietly render wrong):

  • recipes/utilities rank above every starlight.* layer; reset/base/tokens stay below.
  • The statement names every layer the installed Starlight declares — read from the style/layers.css Starlight itself ships, so a version bump that adds a layer fails here rather than in the rendered demos. (An unnamed layer registers on first use and lands last, above utilities, undoing the fix.)
  • layers.css is first in customCss.

Full suite green (2295 tests), lint + typecheck clean, site build + smoke passes.

🤖 Generated with Claude Code

Both Panda and Starlight ship layered CSS, and a cascade layer's position
is fixed the first time its name is seen — so the docs pages were ordering
the two by accident: Panda's five layers registered first (from panda.css),
putting every `starlight.*` layer above every Panda one.

Starlight's `@layer starlight.reset` sets `* { margin: 0 }`, which then beat
Panda's margin utilities inside the live demos. On TextInput that dropped the
`mt: '-1'` tucking a Field's status message under its input: the message sat
4px lower and detached from its control, unlike the same story in Storybook.

Order the layers explicitly instead, splitting Panda's around Starlight's
rather than promoting them wholesale (which unstyles the docs — Panda's
preflight would outrank Starlight's prose). Panda's `reset`/`base`/`tokens`
stay below, so Starlight keeps the last word over its own chrome; `recipes`
and `utilities` go above, and every rule in them is selected by a `silver-*`
class that only the demos and the site's own islands carry.

Verified in a headless browser against the built site: the status message now
computes `margin-top: -4px` on the docs, matching Storybook exactly, and the
prose pages are unchanged.
@czarandy czarandy enabled auto-merge (squash) July 11, 2026 04:52
@czarandy czarandy merged commit 7c76721 into main Jul 11, 2026
1 check passed
@czarandy czarandy deleted the worktree-fix-docs-textinput-status-position branch July 11, 2026 04:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant