Skip to content

feat(core): let CheckboxInput and Switch name their own label theme target - #5183

Open
freddymeta wants to merge 4 commits into
mainfrom
feat/field-label-layout-variant
Open

feat(core): let CheckboxInput and Switch name their own label theme target#5183
freddymeta wants to merge 4 commits into
mainfrom
feat/field-label-layout-variant

Conversation

@freddymeta

@freddymeta freddymeta commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

What

CheckboxInput and Switch now name their own label as a theme target —
astryx-checkbox-label and astryx-switch-label — alongside the
astryx-field-label every label already carries.

A theme could previously only reach one astryx-field-label target, so styling
a checkbox's label (which shares a row with its control) meant styling every
form field's label above its input too.

Why not the layout prop this PR started with

Review was right to hold it, and for a reason that went further than the API
shape:

  • layout was an encoding the label could not verify. A consumer could pass
    layout="beside" on a stacked label and the theme would quietly believe it.
  • The label cannot know how it was arranged — that is its caller's business.
  • There are three placements, not two. Field direction="horizontal-labels"
    also sits a label beside its control, and would have reported stacked, so a
    theme's stacked rule (say, a bottom margin) would land on it and drift the
    label off its input.

The control knows what kind of label it owns, so it passes the target down:

<FieldLabel {...themeProps('checkbox-label')}  />

FieldLabel composes it onto the astryx-field-label it already renders. The
name says what the thing is rather than how it is arranged, nothing can set it
untruthfully, and the horizontal-labels case needs nothing at all — no label
claims a placement any more.

Test plan

  • New tests on all three components: the two classes compose onto one element,
    and FieldLabel asserts it emits no data-layout of its own. Removing each
    themeProps(...) spread fails exactly the matching test
    — verified in both
    directions.
  • The targets are documented on their own component (EN + zh), which is what
    makes them checked: themingTargets.test.ts fails when a rendered
    astryx-* class is missing from that component's doc. Verified by removing
    each doc entry in turn.
  • pnpm test 533 files / 10899 tests, lint:strict 0 errors, pnpm build,
    and every typecheck the build-storybook job runs — including
    typecheck:docs, which is a separate gate from typecheck and the one that
    caught an unsupported description key on a theming target.
  • Reverts the visualProps: ['layout'] this had added to astryx-field-label
    in Field.doc.mjs. Current main is merged in.

…ol labels

FieldLabel always emitted themeProps('field-label') with no variant, so a theme could not distinguish a label stacked above a field from one sitting beside its control (CheckboxInput, Switch). Add a 'layout' prop ('stacked' | 'beside', default 'stacked') reflected as data-layout, and pass 'beside' from CheckboxInput and Switch. Themes can now drop the stacked bottom margin for beside-control labels so the text stays vertically centered.
@vercel

vercel Bot commented Aug 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Ready Ready Preview Aug 20, 2026 6:22am

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 18, 2026
@github-actions github-actions Bot added community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge labels Aug 18, 2026
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

Modified Components

CheckboxInput (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 321 -
Complexity N/A Very High (38) -
Field (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 734 -
Complexity N/A Very High (48) -
Switch (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 497 -
Complexity N/A Very High (46) -

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.8KB 1.2KB

Accessibility Audit

Status: No accessibility violations detected.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

@cixzhang cixzhang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — a theme genuinely can't tell a checkbox label from a form label today, so this is a real gap.

I'd rather not solve it with a prop, though. layout changes nothing but the data- attribute, so a consumer can pass layout="beside" on a stacked label and the theme quietly lies. It's also not theirs to know: CheckboxInput and Switch already know they're a control row.

Could the control pass a target down instead?

<FieldLabel {...themeProps('checkbox-label')}  />

Then a theme names the thing it wants rather than knowing an encoding, nobody can set it untruthfully, and it matches how the other targets landed recently.

It also sidesteps a case this misses: Field direction="horizontal-labels" puts a label beside its control and still reports stacked, so the stacked bottom margin lands on it — I applied it in Chrome and those labels drift off their inputs.

[Reviewed by Robohands, edited by Cindy]

…arget

Replaces the `layout` prop with the shape review asked for. `layout` was an
encoding the label could not verify: a consumer could pass `layout="beside"`
on a stacked label and the theme would quietly believe it, and the label has
no way to know how its caller arranged it. Three placements exist, not two —
`Field direction="horizontal-labels"` also sits a label beside its control and
would have reported `stacked`, so a theme's stacked rule would land on it.

The control passes its own target down instead: CheckboxInput spreads
`themeProps('checkbox-label')` and Switch `themeProps('switch-label')` into
FieldLabel, which composes them onto the `astryx-field-label` it already
renders. A theme now names the thing it wants rather than an arrangement,
nobody can set it untruthfully, and the horizontal-labels case needs nothing
because no label claims a placement any more.

Both targets are documented on their own component (EN + zh), which is also
what makes them checked: themingTargets.test.ts fails if a rendered
`astryx-*` class is missing from that component's doc — verified by removing
each entry in turn. Reverts the `visualProps: ['layout']` this had added to
`astryx-field-label` in Field.doc.mjs.
…targets

`ComponentThemingTarget` is `{className, visualProps?, states?,
deprecatedFor?}` — no `description`. `pnpm -F @astryxdesign/core typecheck:docs`
rejects the extra key, and that is a SEPARATE gate from the `typecheck` I ran:
both live in the build-storybook job, which is why the docs typecheck is the
one that caught this. The two targets carry a class name only, like
`astryx-card`; what they are for is in the changeset.

Also merges current main (clean) so the branch is checked against it.
@freddymeta freddymeta changed the title feat(core): reflect FieldLabel layout as data-layout for beside-control labels feat(core): let CheckboxInput and Switch name their own label theme target Aug 20, 2026
github-actions Bot added a commit that referenced this pull request Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants