A set of helpful input components that take the burden out of building forms with React.
This library depends on @stackup/form to manage the state of form values.
Manages the state of a boolean value using a checkbox.
In addition to the props listed below, this component accepts all props for an HTML input.
<Checkbox
label="I agree"
help="Did you read all 7,000 lines?"
field={useField(form, "confirmation")}
/>
Name | Type | Required | Description |
---|---|---|---|
field | FormField<boolean> |
✓ | See @stackup/form |
label | ReactNode |
✓ | Content to appear in the label |
help | ReactNode |
✗ | Extra help info that will be rendered within the label |
variant | string | boolean | FieldVariant[] |
✗ | Variant class name to append to all elements |
prepend | ReactNode |
✗ | Content to render before the input |
append | ReactNode |
✗ | Content to render after the input |
className | string |
✗ | An additional class name for the field |
inputClassName | string |
✗ | An additional class name for the input |
labelClassName | string |
✗ | An additional class name for the label |
helpClassName | string |
✗ | An additional class name for the help |
errorClassName | string |
✗ | An additional class name for the error |
innerRef | Ref<HTMLInputElement> |
✗ | A ref to the input element |
Manages an array of values, represented by checkboxes.
In addition to the props listed below, this component accepts all props for an HTML input.
Note that this component will not render error messages. For that, you'll want to wrap your checkboxes in a FieldSet.
<FieldSet legend="Sport" field={useField(form, "sport")}>
<CheckboxItem
label="Soccer"
value={{ name: "Soccer" }}
field={useField(form, "sport")}
/>
<CheckboxItem
label="Baseball"
value={{ name: "Baseball" }}
field={useField(form, "sport")}
/>
</FieldSet>
Name | Type | Required | Description |
---|---|---|---|
value | Value |
✓ | Toggle the inclusion of this value in the array. |
field | FormField<Value[]> |
✓ | See @stackup/form |
label | ReactNode |
✓ | Content to appear in the label |
help | ReactNode |
✗ | Extra help info that will be rendered within the label |
variant | string | boolean | FieldVariant[] |
✗ | Variant class name to append to all elements |
prepend | ReactNode |
✗ | Content to render before the input |
append | ReactNode |
✗ | Content to render after the input |
className | string |
✗ | An additional class name for the field |
inputClassName | string |
✗ | An additional class name for the input |
labelClassName | string |
✗ | An additional class name for the label |
helpClassName | string |
✗ | An additional class name for the help |
errorClassName | string |
✗ | An additional class name for the error |
innerRef | Ref<HTMLInputElement> |
✗ | A ref to the input element |
Fields that are composed of multiple components (e.g. Radio and CheckboxItem) should always be rendered within a fieldset.
If an error is associated with the field, it will be rendered within the fieldset, rather than on a Radio or CheckboxItem.
<FieldSet legend="Sport" field={useField(form, "sport")}>
<Radio
label="Soccer"
value={{ name: "Soccer" }}
field={useField(form, "sport")}
/>
<Radio
label="Baseball"
value={{ name: "Baseball" }}
field={useField(form, "sport")}
/>
</FieldSet>
Name | Type | Required | Description |
---|---|---|---|
field | FormField<any> |
✓ | See @stackup/form |
legend | ReactNode |
✓ | Content to appear in the legend |
help | ReactNode |
✗ | Extra help info |
children | ReactNode |
✗ | Content that should appear inside the fieldset |
variant | string | boolean | FieldVariant[] |
✗ | Variant class name to append to all elements |
className | string |
✗ | An additional class name for the fieldset |
legendClassName | string |
✗ | An additional class name for the legend |
helpClassName | string |
✗ | An additional class name for the help |
errorClassName | string |
✗ | An additional class name for the error |
Renders an <input type="file" />
.
In addition to the props listed below, this component accepts all props for an HTML input.
<FileInput label="Image" field={useField(form, "image")} />
Name | Type | Required | Description |
---|---|---|---|
field | FormField<File> |
✓ | See @stackup/form |
label | ReactNode |
✓ | Content to appear in the label |
help | ReactNode |
✗ | Extra help info that will be rendered within the label |
variant | string | boolean | FieldVariant[] |
✗ | Variant class name to append to all elements |
prepend | ReactNode |
✗ | Content to render before the input |
append | ReactNode |
✗ | Content to render after the input |
className | string |
✗ | An additional class name for the field |
inputClassName | string |
✗ | An additional class name for the input |
labelClassName | string |
✗ | An additional class name for the label |
helpClassName | string |
✗ | An additional class name for the help |
errorClassName | string |
✗ | An additional class name for the error |
innerRef | Ref<HTMLInputElement> |
✗ | A ref to the input element |
Renders an <input type="file" multiple />
.
In addition to the props listed below, this component accepts all props for an HTML input.
<FileListInput label="Images" field={useField(form, "images")} />
Name | Type | Required | Description |
---|---|---|---|
field | FormField<FileList> |
✓ | See @stackup/form |
label | ReactNode |
✓ | Content to appear in the label |
help | ReactNode |
✗ | Extra help info that will be rendered within the label |
variant | string | boolean | FieldVariant[] |
✗ | Variant class name to append to all elements |
prepend | ReactNode |
✗ | Content to render before the input |
append | ReactNode |
✗ | Content to render after the input |
className | string |
✗ | An additional class name for the field |
inputClassName | string |
✗ | An additional class name for the input |
labelClassName | string |
✗ | An additional class name for the label |
helpClassName | string |
✗ | An additional class name for the help |
errorClassName | string |
✗ | An additional class name for the error |
innerRef | Ref<HTMLInputElement> |
✗ | A ref to the input element |
Renders an <input />
, which whatever type you provide.
The value of this input will always be a string, but you should use a validation library such as @stackup/validate to parse and validate the entry before submission.
In addition to the props listed below, this component accepts all props for an HTML input.
<Input type="email" label="Email" field={useField(form, "email")} />
Name | Type | Required | Description |
---|---|---|---|
type | InputType |
✗ | |
field | FormField<string> |
✓ | See @stackup/form |
label | ReactNode |
✓ | Content to appear in the label |
help | ReactNode |
✗ | Extra help info that will be rendered within the label |
variant | string | boolean | FieldVariant[] |
✗ | Variant class name to append to all elements |
prepend | ReactNode |
✗ | Content to render before the input |
append | ReactNode |
✗ | Content to render after the input |
className | string |
✗ | An additional class name for the field |
inputClassName | string |
✗ | An additional class name for the input |
labelClassName | string |
✗ | An additional class name for the label |
helpClassName | string |
✗ | An additional class name for the help |
errorClassName | string |
✗ | An additional class name for the error |
innerRef | Ref<HTMLInputElement> |
✗ | A ref to the input element |
Renders an <input type="radio" />
and manages the state of any type of value.
Note that this component will not render error messages. For that, you'll want to wrap your radio options in a FieldSet.
In addition to the props listed below, this component accepts all props for an HTML input.
<FieldSet legend="Sport" field={useField(form, "sport")}>
<Radio
label="Soccer"
value={{ name: "Soccer" }}
field={useField(form, "sport")}
/>
<Radio
label="Baseball"
value={{ name: "Baseball" }}
field={useField(form, "sport")}
/>
</FieldSet>
Name | Type | Required | Description |
---|---|---|---|
value | Value |
✓ | The value of the option to be selected |
field | FormField<Value> |
✓ | See @stackup/form |
label | ReactNode |
✓ | Content to appear in the label |
help | ReactNode |
✗ | Extra help info that will be rendered within the label |
variant | string | boolean | FieldVariant[] |
✗ | Variant class name to append to all elements |
prepend | ReactNode |
✗ | Content to render before the input |
append | ReactNode |
✗ | Content to render after the input |
className | string |
✗ | An additional class name for the field |
inputClassName | string |
✗ | An additional class name for the input |
labelClassName | string |
✗ | An additional class name for the label |
helpClassName | string |
✗ | An additional class name for the help |
errorClassName | string |
✗ | An additional class name for the error |
innerRef | Ref<HTMLInputElement> |
✗ | A ref to the input element |
Renders a <select />
tag with whatever options you provide.
You can provide a placeholder, which will render a disabled option with a blank value.
In addition to the props listed below, this component accepts all props for an HTML select.
<Select
label="Sport"
placeholder="Choose a sport"
field={useField(form, "sport")}
>
<option value="baseball">Baseball</option>
<option value="soccer">Soccer</option>
</Select>
Name | Type | Required | Description |
---|---|---|---|
placeholder | string |
✗ | |
field | FormField<string> |
✓ | See @stackup/form |
label | ReactNode |
✓ | Content to appear in the label |
help | ReactNode |
✗ | Extra help info that will be rendered within the label |
variant | string | boolean | FieldVariant[] |
✗ | Variant class name to append to all elements |
prepend | ReactNode |
✗ | Content to render before the input |
append | ReactNode |
✗ | Content to render after the input |
className | string |
✗ | An additional class name for the field |
inputClassName | string |
✗ | An additional class name for the input |
labelClassName | string |
✗ | An additional class name for the label |
helpClassName | string |
✗ | An additional class name for the help |
errorClassName | string |
✗ | An additional class name for the error |
innerRef | Ref<HTMLSelectElement> |
✗ | A ref to the input element |
Renders a <button />
to toggle the state of a boolean value.
You can style this element with CSS by selecting the [aria-checked]
value.
In addition to the props listed below, this component accepts all props for an HTML button.
<Switch type="enabled" label="Show preview" field={useField(form, "enabled")} />
Name | Type | Required | Description |
---|---|---|---|
field | FormField<boolean> |
✓ | See @stackup/form |
label | ReactNode |
✓ | Content to appear in the label |
help | ReactNode |
✗ | Extra help info that will be rendered within the label |
variant | string | boolean | FieldVariant[] |
✗ | Variant class name to append to all elements |
prepend | ReactNode |
✗ | Content to render before the input |
append | ReactNode |
✗ | Content to render after the input |
className | string |
✗ | An additional class name for the field |
inputClassName | string |
✗ | An additional class name for the input |
labelClassName | string |
✗ | An additional class name for the label |
helpClassName | string |
✗ | An additional class name for the help |
errorClassName | string |
✗ | An additional class name for the error |
innerRef | Ref<HTMLButtonElement> |
✗ | A ref to the input element |
Renders a <textarea />
.
In addition to the props listed below, this component accepts all props for an HTML input.
<TextArea type="comment" label="Comment" field={useField(form, "comment")} />
Name | Type | Required | Description |
---|---|---|---|
field | FormField<string> |
✓ | See @stackup/form |
label | ReactNode |
✓ | Content to appear in the label |
help | ReactNode |
✗ | Extra help info that will be rendered within the label |
variant | string | boolean | FieldVariant[] |
✗ | Variant class name to append to all elements |
prepend | ReactNode |
✗ | Content to render before the input |
append | ReactNode |
✗ | Content to render after the input |
className | string |
✗ | An additional class name for the field |
inputClassName | string |
✗ | An additional class name for the input |
labelClassName | string |
✗ | An additional class name for the label |
helpClassName | string |
✗ | An additional class name for the help |
errorClassName | string |
✗ | An additional class name for the error |
innerRef | Ref<HTMLTextAreaElement> |
✗ | A ref to the input element |
Render a ThemeProvider
at the top of your component tree
to provide a global theme.
See createTheme
for an example of how to define your theme.
<ThemeProvider value={theme}>
<App />
</ThemeProvider>
Concatenate multiple class names.
concat("field", touched && error && "field--invalid");
Create a new theme. This can be used in combination with the ThemeProvider to apply class names to fields.
export const theme = createTheme({
field: props => {
return concat(
"field",
props.touched && props.error && "field--invalid",
...props.types.map(type => `field--${type}`),
...props.variants.map(variant => variant && `field--${variant}`)
);
}
});
Convert ISO-8601 to input[type=datetime-local]
. This can be used to populate
the initial value for your inputs.
When given an invalid value, this function will throw an error.
formatDateTime("2020-07-08T16:30:00.000Z");
Convert ISO-8601 to input[type=time]
. This can be used to populate
the initial value for your inputs.
When given an invalid value, this function will throw an error.
formatTime("08:28:00Z");
Convert a number to input[type=number]
. This can be used to populate
the initial value for your inputs.
When given an invalid value, this function will throw an error.
formatNumber(0);
Convert input[type=datetime-local]
to ISO-8601. This can be used to parse and validate
information entered by the user.
When given an invalid value, this function will return undefined
.
parseDateTime("2020-07-08T12:30");
Convert input[type=time]
to ISO-8601. This can be used to parse and validate
information entered by the user.
When given an invalid value, this function will return undefined
.
parseTime("04:28");
Convert input[type=number]
to a number. This can be used to parse and validate
information entered by the user.
When given an invalid value, this function will return undefined
.
parseNumber("1");