Skip to content

feat(components): [DSYS-194] add description and errorMessage props to field components#1941

Closed
ShreyasGit51283 wants to merge 1 commit into
mainfrom
dsys-194-field-description-prop
Closed

feat(components): [DSYS-194] add description and errorMessage props to field components#1941
ShreyasGit51283 wants to merge 1 commit into
mainfrom
dsys-194-field-description-prop

Conversation

@ShreyasGit51283

@ShreyasGit51283 ShreyasGit51283 commented Jun 25, 2026

Copy link
Copy Markdown

Summary

Resolves the description prop drift between the LaunchPad React components and the Figma library (DSYS-194).

The Figma library exposes a flat description property on field components, but in code helper text was only expressible as a slotted child (<Text slot="description">). This mismatch broke Code Connect mappings.

This PR adds ergonomic description and errorMessage props to the field wrappers, implemented through a single shared helper so the slot-rendering logic lives in exactly one place.

  • New renderFieldHelpers() + FieldHelperProps in src/fieldHelpers.tsx — the single source of truth that renders the RAC <Text slot="description"> and <FieldError> slots.
  • Props added to: TextField, NumberField, SearchField, Select, ComboBox, RadioGroup, CheckboxGroup, DateField, TimeField.
  • Single controls (Checkbox, Switch, Radio, Label) intentionally not changed — per RAC/React Spectrum convention, helper text belongs at the group level.
  • Code Connect (.figma.tsx) mappings updated to map Figma's description to the new prop.
  • TextField story updated (prop + back-compat slot story) with a play test asserting render + aria-describedby wiring.
  • minor changeset (additive, non-breaking — existing slotted children keep working).

Review focus

Please review TextField first — it is the reference implementation. Scrutinize:

  • src/fieldHelpers.tsx (the shared helper — the only real logic)
  • src/TextField.tsx
  • figma/TextField.figma.tsx

The other 8 components apply the identical mechanical change: destructure description, errorMessage out of props and route children through renderFieldHelpers. Once the TextField approach is approved, the rest are replicas.

Test plan

  • pnpm --filter @launchpad-ui/components test — run the TextField play test
  • Storybook: verify the TextField Example renders the description and DescriptionAsSlot still works
  • figma connect publish validation — confirm the Figma Description property/layer names in the updated .figma.tsx files match the actual Figma components (several were added following the existing 'Description?' / 'Description' convention and need verification against the live file)

Made with Cursor


Open in Devin Review

…o field components

Introduces a shared renderFieldHelpers() helper and adds ergonomic
`description`/`errorMessage` props to TextField, NumberField, SearchField,
Select, ComboBox, RadioGroup, CheckboxGroup, DateField, and TimeField.
The props render the React Aria description slot and FieldError internally,
matching the Figma library's flat `description` property and resolving the
Code Connect drift. Additive and non-breaking: existing slotted children
keep working.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ShreyasGit51283 ShreyasGit51283 requested a review from a team as a code owner June 25, 2026 15:40
@changeset-bot

changeset-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a7e5e3a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@launchpad-ui/components Minor

Not sure what this means? Click here to learn what changesets are.

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

@pkg-pr-new

pkg-pr-new Bot commented Jun 25, 2026

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

commit: a7e5e3a

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a7e5e3a. Configure here.

<Provider values={[[GroupContext, { isInvalid, isDisabled }]]}>{children}</Provider>
<Provider values={[[GroupContext, { isInvalid, isDisabled }]]}>
{renderFieldHelpers(children, { description, errorMessage })}
</Provider>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Context helper props ignored

Medium Severity

description and errorMessage are taken from props before useLPContextProps runs, so values supplied only through each field’s LaunchPad context never reach renderFieldHelpers. Those merged keys can still be spread onto the React Aria wrapper via {...props}.

Additional Locations (2)
Fix in Cursor Fix in Web

Triggered by project rule: Bugbot Instructions — launchpad-ui

Reviewed by Cursor Bugbot for commit a7e5e3a. Configure here.

@devin-ai-integration devin-ai-integration Bot 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.

Devin Review found 1 potential issue.

View 1 additional finding in Devin Review.

Open in Devin Review

* https://react-spectrum.adobe.com/react-aria/CheckboxGroup.html
*/
const CheckboxGroup = ({ ref, ...props }: CheckboxGroupProps) => {
const CheckboxGroup = ({ ref, description, errorMessage, ...props }: CheckboxGroupProps) => {

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.

🟡 Field helper props provided through context are silently ignored and leak to the DOM

The description and error message are extracted from the component's input ({ ref, description, errorMessage, ...props } at packages/components/src/CheckboxGroup.tsx:27) before context values are merged in, so any values supplied through the public context are never rendered as helper text and instead leak as unknown attributes.

Impact: Consumers using the exported context (e.g. CheckboxGroupContext) to set description or error message will see no visible helper text and may get React warnings about unrecognized DOM properties.

Destructuring order breaks the established context-merge pattern

The established pattern across all components in this codebase is to only destructure ref before calling useLPContextProps, because ref requires special handling via mergeRefs (packages/components/src/utils.tsx:88). All other props flow through context merging.

This PR destructures description and errorMessage before the context merge in all 9 affected components:

  • packages/components/src/CheckboxGroup.tsx:27
  • packages/components/src/RadioGroup.tsx:27
  • packages/components/src/TextField.tsx:29
  • packages/components/src/NumberField.tsx:27
  • packages/components/src/SearchField.tsx:27
  • packages/components/src/DateField.tsx:58-63
  • packages/components/src/DateField.tsx:119-124 (TimeField)
  • packages/components/src/Select.tsx:42
  • packages/components/src/ComboBox.tsx:36-41

The context types include FieldHelperProps because they're typed as ContextValue<XxxProps, HTMLDivElement> and XxxProps now extends FieldHelperProps. So TypeScript allows providing these via context, but the runtime ignores them.

The fix is to destructure description and errorMessage AFTER useLPContextProps, e.g.:

const CheckboxGroup = ({ ref, ...props }: CheckboxGroupProps) => {
  [props, ref] = useLPContextProps(props, ref, CheckboxGroupContext);
  const { description, errorMessage, ...restProps } = props;
  return (
    <AriaCheckboxGroup {...restProps} ref={ref} ...>
      {composeRenderProps(restProps.children, (children) =>
        renderFieldHelpers(children, { description, errorMessage }),
      )}
    </AriaCheckboxGroup>
  );
};
Prompt for agents
In all 9 affected field components (CheckboxGroup, RadioGroup, TextField, NumberField, SearchField, DateField, TimeField, Select, ComboBox), the description and errorMessage props are destructured from the component arguments BEFORE useLPContextProps merges context-provided values. This breaks the established pattern where only ref is destructured before context merging.

The fix for each component is to move the destructuring of description and errorMessage to AFTER the useLPContextProps call, and then pass the remaining props (without description/errorMessage) to the underlying RAC component. For example in CheckboxGroup.tsx:

1. Change the function signature to only destructure ref: ({ ref, ...props })
2. After useLPContextProps, destructure: const { description, errorMessage, ...restProps } = props;
3. Pass restProps (not props) to AriaCheckboxGroup and restProps.children to composeRenderProps
4. Continue passing description and errorMessage to renderFieldHelpers

Apply the same pattern to all 9 components: CheckboxGroup.tsx, RadioGroup.tsx, TextField.tsx, NumberField.tsx, SearchField.tsx, DateField.tsx (both DateField and TimeField), Select.tsx, and ComboBox.tsx.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +13 to +22
const renderFieldHelpers = (
children: ReactNode,
{ description, errorMessage }: FieldHelperProps,
) => (
<>
{children}
{description != null && <Text slot="description">{description}</Text>}
{errorMessage != null && <FieldError>{errorMessage}</FieldError>}
</>
);

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.

@apucacao @zakk-verrilli-ld
we've always approach launchpad component in composable architecture, and this approach seems to go against that.

do we want to expose description/error as props? or just direct develops to use the slot to render error/descriptions?

@apucacao apucacao Jun 25, 2026

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.

Seems simpler to me do use the slot API, but I don't have much context around this change. Is this just about ergonomics? Agents and humans seem to deal with slots fine, and — assuming it is mostly about ergonomics — I'd argue adding another mechanism of providing values for these slots could add confusion: 2 ways of doing the exact same thing?

@zakk-verrilli-ld zakk-verrilli-ld Jun 25, 2026

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.

Agreed slots are the way. Both description and errorMessage are (in some cases the exclusive) slots for field components already.

RAC Source

Is the issue here that Figma Code Connect is not wired up to generate the subcomponents? Slack Thread

@ShreyasGit51283

Copy link
Copy Markdown
Author

@zakk-verrilli-ld reccomends we should explore fixing the Code connect generator. Closing this PR to explore that route

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.

4 participants