Roadie provides a set of composable form components that handle accessibility,
validation states, and styling automatically. This page covers the patterns and
best practices for assembling them into forms.
Field, Select, and RadioGroup all use React context to flow state to their
children. Set invalid, required, and disabled on the root — child inputs
pick up the corresponding aria attributes automatically.
<Fieldset><Fieldrequired><Field.LabelshowIndicator>Email</Field.Label><Field.Inputtype='email'placeholder='you@example.com'/></Field><Fieldinvalid><Field.Label>Password</Field.Label><Field.Inputtype='password'defaultValue='short'/><Field.ErrorText>Password must be at least 8 characters.</Field.ErrorText></Field><Fielddisabled><Field.Label>Username</Field.Label><Field.InputdefaultValue='taken-name'/><Field.HelperText>This field cannot be changed.</Field.HelperText></Field></Fieldset>
Indicators
Use showIndicator on any label component (Field.Label, Select.Label,
RadioGroup.Label) to automatically render a required or optional indicator
based on the parent's required prop. This eliminates the need to manually
import and place RequiredIndicator or OptionalIndicator.
Field wraps any form control — not just Input and Textarea. Use it with Select,
RadioGroup, Combobox, and Autocomplete for consistent layout, labels, and error
handling. Field provides grid gap-1.5 spacing, label wiring, and
invalid/required/disabled context that child controls inherit automatically.
Use Select.Content instead of manually nesting Portal, Positioner, and Popup.
Pass string children to Select.Item for automatic ItemText and
ItemIndicator wrapping. The individual primitives remain available for
advanced customisation.
Error handling
Field.ErrorText only renders when the parent Field has invalid set.
Select.ErrorText and RadioGroup.ErrorText hide when invalid is explicitly
false. This means you can always include the error text in your markup without
conditional wrappers.
<Fieldset><Fieldinvalidrequired><Field.LabelshowIndicator>Email</Field.Label><Field.Inputtype='email'/><Field.ErrorText>Please enter a valid email address.</Field.ErrorText></Field><Fieldrequired><Field.LabelshowIndicator>Name</Field.Label><Field.InputdefaultValue='Luke'/><Field.ErrorText>This error is hidden because the field is valid.</Field.ErrorText></Field></Fieldset>
Grouping fields
Use Fieldset with Fieldset.Legend to group related fields. This provides
semantic HTML grouping and a visible legend for screen readers.
Set invalid on the Field root to show error states across any control.
Field.ErrorText auto-hides when invalid is falsy.
<Fieldset><Fieldinvalidrequired><Field.LabelshowIndicator>Email</Field.Label><Field.Inputtype='email'/><Field.ErrorText>Please enter a valid email address.</Field.ErrorText></Field><Fieldinvalidrequired><Field.LabelshowIndicator>Industry</Field.Label><Select><Select.Trigger><Select.Valueplaceholder='Select...'/><Select.Icon/></Select.Trigger><Select.Content><Select.Itemvalue='music'>Music</Select.Item><Select.Itemvalue='sport'>Sport</Select.Item></Select.Content></Select><Field.ErrorText>Please select an industry.</Field.ErrorText></Field><Fieldinvalidrequired><Field.LabelshowIndicator>Contact method</Field.Label><RadioGroup><RadioGroup.Itemvalue='email'label='Email'/><RadioGroup.Itemvalue='phone'label='Phone'/></RadioGroup><Field.ErrorText>Please select a contact method.</Field.ErrorText></Field></Fieldset>
Guidelines
Do
Wrap all form controls in Field for consistent layout, labels, and error handling
Set invalid, required, and disabled on the Field root — child controls inherit these automatically
Use Field.Label with showIndicator for all form control labels
Use Field.ErrorText and Field.HelperText for feedback text
Use Select.Content for standard dropdowns
Use Fieldset with Fieldset.Legend to group related fields
Don't
Don't pass aria-invalid manually — Field context handles it
Don't import RequiredIndicator or OptionalIndicator directly when using showIndicator