Skip to content

fix(shadcn): field wrapper trio declared right-side-up — resolves #40 (3.2.0) - #42

Merged
ryandmonk merged 1 commit into
mainfrom
feat/field-family-correction
Aug 7, 2026
Merged

fix(shadcn): field wrapper trio declared right-side-up — resolves #40 (3.2.0)#42
ryandmonk merged 1 commit into
mainfrom
feat/field-family-correction

Conversation

@ryandmonk

Copy link
Copy Markdown
Contributor

Grounded in the real shadcn API (field.tsx: FieldSet is a <fieldset>, FieldLegend its <legend>; docs prescribe FieldSet > FieldLegend + FieldGroup > Field) and in measured usage (field-label 9/9 and field-description 5/5 inside field; the wrapper trio 0/6 — always above it). The contract's own composition notes prescribed the correct hierarchy while the declaration inverted it, which made ex.notification-preferences an orphaned-sub surface under spec v0.4 §5.1 (dspack#41).

  • field-set and field-group promoted to top-level components; field-legend (with its legend slot) moves under field-set, field-separator under field-group.
  • field keeps content/label/title/description/error.
  • Set-level FieldDescription: upstream allows it; this contract deliberately narrows it to Field scope, now stated in the notes.
  • rule.field-set-carries-a-legend untouched (anchors stay valid).
  • Convergence proof: all 14 worked examples pass the new S2 containment gate (dspack-gen#53) under this declaration; the exemplar fails under the inverted one (pinned in containment.test.ts).

Closes #40. Version 3.2.0.

🤖 Generated with Claude Code

…40 (3.2.0)

First-principles from the real API (field.tsx + the component docs):
FieldSet renders a <fieldset> whose <legend> is FieldLegend — the one true
HTML ownership in the family; FieldGroup stacks Fields and hosts
FieldSeparator between sections; Field wraps ONE control with its label,
title, description, error, and content. The canonical nesting is
FieldSet > FieldLegend + FieldGroup > Field — the wrappers sit ABOVE
field, and the contract's own composition notes already said so verbatim
while the declaration said the opposite.

Measured usage agreed with the notes, not the declaration: across all 14
worked examples, field-label (9/9) and field-description (5/5) appear only
inside field, while field-set/field-legend/field-group appear only OUTSIDE
it (the ex.notification-preferences exemplar), which made the contract's
own exemplar an orphaned-sub surface under spec v0.4 §5.1.

The correction, additive at the vocabulary level (no id changes):

- field-set → top-level component; owns field-legend (slot 'legend'
  rides with it);
- field-group → top-level component; owns field-separator (its own
  description places it 'between sections of a FieldGroup');
- field keeps its genuine inner parts: field-content, field-label,
  field-title, field-description, field-error;
- composition notes updated: the wrappers are top-level here, and the
  upstream set-level FieldDescription is deliberately narrowed to Field
  scope (every shipped example uses it there; a set-level summary belongs
  to the legend);
- rule.field-set-carries-a-legend unchanged — it anchors field-legend
  within field-set, and both remain valid lint-time nodes.

Convergence with the §5.1 containment gate, verified: all 14 worked
examples pass the new S2 under this declaration (the exemplar failed under
the inverted one — pinned in dspack-gen's containment.test.ts).

Version 3.2.0. Validator + example suite + lib boundary green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 7, 2026 21:10

Copilot AI 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.

Copilot wasn't able to review any files in this pull request.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ryandmonk
ryandmonk merged commit d50f049 into main Aug 7, 2026
1 check passed
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.

Contract gap: the field wrapper trio is declared upside-down (field-set/field-legend/field-group as subs of field)

2 participants