Skip to content

docs(components): add Forms guidelines page to Storybook - #1961

Draft
cmwinters wants to merge 3 commits into
mainfrom
cwinters/docs/form-guideline-scaffold
Draft

docs(components): add Forms guidelines page to Storybook#1961
cmwinters wants to merge 3 commits into
mainfrom
cwinters/docs/form-guideline-scaffold

Conversation

@cmwinters

@cmwinters cmwinters commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a Forms overview page at the root of the Components/Forms group — a home for written guidance, which the design system didn't have. Storybook carried API references (autodocs) and live examples (stories, recipes), but nowhere to say "here is how to compose a form."

Clicking Forms in the sidebar now opens this overview; expanding it still lists the ten form components. A docs entry whose title matches a folder path coexists with that folder's children without conflict, so this needed zero config change.

Files sit alongside the stories they document — Forms.mdx and Forms.stories.tsx next to Form.stories.tsx. Their header comment flags that these are cross-cutting form examples rather than the Form component's own stories, since the singular/plural filenames are easy to confuse.

The main thing this page fixes

No form component accepts label, description, errorMessage or placeholder as a prop. React Aria deliberately Omits them — they're React Spectrum props. The real pattern is slot composition:

<TextField isRequired>
	<Label>Email</Label>
	<Input placeholder="Enter a value" />   {/* placeholder is on Input */}
	<Text slot="description">Helper text</Text>
	<FieldError />
</TextField>

This is easy to get wrong because AGENTS.md:59 mentions description/errorMessage as the naming convention to mirror if you ever add such a prop — not as a description of today's API. The page quotes the .d.ts Omit directly so it can't drift.

Three gaps recorded rather than papered over

  1. Required fields render no visible marker. isRequired sets aria-required and native required, but Label has no isRequired awareness. The deprecated @launchpad-ui/form had RequiredAsterisk and an (optional) suffix — neither has a modern equivalent.
  2. FieldError has no icon and no live region. Styled text only; the deprecated package had an alert icon with aria-live="polite".
  3. Helper text fails colour contrast in picker itemsSelect/ComboBox stories suppress the axe color-contrast rule for [slot="description"] rather than fixing the token.

These are arguably the strongest argument for the page: they're invisible today. Each deserves its own ticket.

Content guidelines are a scaffold with a named gap

Per the agreed approach, wording rules are not invented here. I searched exhaustively — the repo has no written copy standards: zero hits for "copy standard", "sentence case", "title case", "content guideline", "microcopy", "voice", "tone", "capitalization" across all markdown, MDX and code. Commit 157f6971 ("follow our copy standards") is a one-line story edit ("Secondary action""Cancel").

So that section lists the questions a content designer needs to answer, plus the de facto conventions observable in our stories as raw material. It needs an owner — either someone supplies a canonical LD content-standard URL to link, or this page becomes the first written version.

Screenshots (if appropriate)

⚠️ Not attached — I have no browser tooling in this environment. Verified structurally instead (below), but the visual pass is genuinely unverified: reading the page in dark mode, and confirming each <Canvas> renders live rather than an error placeholder. Please eyeball those, or the Chromatic snapshots will.

Testing approaches

Verified against the built Storybook output rather than by eye:

  • pnpm storybook:build exits 0 — the MDX compiles
  • index.json shows components-forms--docs with title: 'Components/Forms', type docs, tag unattached-mdx
  • That entry coexists with all 44 Components/Forms/* child entries with no duplicate-title conflict — verified by rebuilding after the retitle
  • The companion story file leaks no sidebar entries — its stories resolve to tags ['test'] with dev and autodocs stripped, exactly matching how recipes/composition.stories.tsx indexes
  • The compiled docs chunk references forms.stories and all five story symbols, so the <Canvas of={...}> imports bundle correctly
  • toc:!0 present in the chunk — the docs.toc parameter does take effect on an unattached MDX page (this was the uncertain bit; nothing else in the repo sets it)
  • pnpm typecheck and pnpm check clean
  • Slot usage cross-checked against existing CheckboxGroup/RadioGroup stories, since a slot mismatch throws at render (see DSYS-157)

Examples are written as real stories, not fenced code blocks, so they're type-checked and can't drift from the component APIs. Given the label/description confusion above, a wrong sample would be worse than no page.

Follow-ups worth filing

Found while auditing, all out of scope here:

  • RadioButton.tsx:19-23 has Radio's JSDoc copy-pasted ("A radio represents an individual option…") — it renders as a button. TextArea.tsx:23-27 typo "mult-line". ComboBoxClearButton, CheckboxIcon, RadioIcon exported with no JSDoc. Autodocs is global, so these are public today.
  • No story files for TextArea, Radio, RadioButton, Input, FieldError.
  • Dead CSS: Label.module.css:13-18 keys on a bare orientation attribute but Form.tsx:38 emits data-orientation. Form's horizontal div[data-rac] selector also can't match Checkbox/Radio/Switch (root <label>).
  • Broken axe suppression: ComboBox.stories.tsx:172-178 uses '*not([aria-hidden]...)' — missing the : before not(, so it likely isn't applying.
  • ADR-001 and ADR-007 are stale — both describe Playwright a11y testing, but there's no Playwright dependency or config in the repo and no axe import in any test. Real coverage is the addon-a11y panel plus Chromatic.
  • Nine of twelve Legacy/Form/* stories are untagged, so deprecated form components look like live docs — actively confusing next to a new Forms guidelines page.

Adds the first page under the Guidelines section, which was already reserved
in storySort.order but had no content.

The page documents what the code actually enforces. Its main job is the
composition rule: no form component accepts label, description, errorMessage
or placeholder as a prop, because React Aria omits them in favour of slot
composition. Those are React Spectrum props, and the confusion is easy to hit
since AGENTS.md mentions the names as a convention to mirror rather than as a
description of the current API.

It also records three gaps rather than papering over them: required fields
render no visible marker, FieldError has no icon or live region, and helper
text fails contrast inside picker items. All three regressed from the
deprecated form package or are suppressed in axe config.

Content guidelines are left as an explicitly-owned scaffold. The repo has no
written copy standards to point at, so wording rules are marked as needing a
content designer instead of being invented here.

Examples live in a companion story file tagged ['!dev', '!autodocs'] so they
stay out of the sidebar, following the recipes/composition pattern. Writing
them as real stories rather than fenced code blocks means they are
type-checked and cannot drift from the component APIs.
@changeset-bot

changeset-bot Bot commented Jul 28, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: ab6ee68

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 28, 2026

Copy link
Copy Markdown
yarn add https://pkg.pr.new/@launchpad-ui/components@1961.tgz
yarn add https://pkg.pr.new/@launchpad-ui/icons@1961.tgz
yarn add https://pkg.pr.new/@launchpad-ui/tokens@1961.tgz

commit: ab6ee68

Retitles the page from Guidelines/Forms to Components/Forms so it sits at the
root of the group it describes: clicking "Forms" in the sidebar opens the
overview, and expanding it lists the individual components. A docs entry whose
title matches a folder path coexists with that folder's children without
conflict.

Files move alongside the component stories they document, so Forms.mdx and
Forms.stories.tsx now sit next to Form.stories.tsx rather than in a separate
guidelines directory. Their header comment calls out that these are
cross-cutting form examples and not the Form component's own stories, since the
singular and plural filenames are otherwise easy to confuse.

The intro now frames Select, ComboBox, DateField and TimeField as the field
types living elsewhere in the sidebar, rather than listing the components this
page already nests.
MDX implements CommonMark, not GitHub Flavored Markdown, so table syntax in
docs pages compiled to literal text — visible pipes and dashes rather than a
table. Strikethrough, task lists and bare-URL autolinks fail the same way.

Adds remark-gfm and passes it through addon-docs' mdxPluginOptions so GFM
markdown renders as authored.

Storybook styles no prose tables of its own; only the props argstable is
themed. Without styling a GFM table renders with browser defaults, meaning no
borders or padding, so this also adds table styles for docs prose.

Those rules are scoped to direct children of the docs content container, which
keeps them off tables rendered inside a Canvas by the Table component's own
stories. They use --lp-* tokens rather than this file's hardcoded-hex
convention because .sbdocs only exists in the preview frame, where the token
CSS is loaded and [data-theme] flips the values. The compound class selector
keeps specificity level with the argstable rules so the file stays free of new
descending-specificity lint warnings.
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