Field
A labeled control with an optional hint and error under it, stacked 6 pixels apart. FieldHint and FormError are the same two lines on their own, for a control that is not inside a Field.
import { Field, FieldHint, FormError } from '@basmilius/react-ui';import { useState } from 'react';
import { Field, FieldHint, FormError, Input, Segmented } from '@basmilius/react-ui';
export default function FieldDemo() {
const [name, setName] = useState('feature/export');
const taken = name.trim() === 'main';
const [ground, setGround] = useState('dark');
return (
<div className="flex w-80 flex-col gap-4">
<Field label="Branch name" hint="Lowercase, with slashes for a folder." error={taken ? 'A branch called main already exists.' : null}>
<Input mono value={name} onChange={(event) => setName(event.target.value)} />
</Field>
<Field group label="Ground" hint="What every frame is drawn on.">
<Segmented
label="Ground"
value={ground}
onValueChange={setGround}
options={[
{ id: 'dark', label: 'Dark' },
{ id: 'light', label: 'Light' }
]}
/>
</Field>
<div>
<Input aria-label="Remote URL" placeholder="https://" />
<FieldHint>A hint on its own keeps a margin above it.</FieldHint>
</div>
<FormError>The remote refused the push.</FormError>
</div>
);
}Type main into the branch name to see the error. An Input or a TextArea inside a Field connects itself. The label points at it with htmlFor, aria-describedby names the hint and the error, and an error sets aria-invalid. Another control needs its own accessible name, since the Field cannot reach inside it.
A group
A <label> can point at an input, not at a Segmented, a Select, ChoiceCards or a path in a box with a button beside it. group draws the same label, hint and error with the same spacing, and makes the Field a role="group" its label names and its hint and error describe. The control inside still takes its own accessible name, and an Input inside a group is left unconnected, for an input that is one part of what the group holds.
<Field group label="Folder" hint="The project is made in a new folder here.">
<div className="flex items-center gap-2">
<div className="field flex min-w-0 flex-1 items-center text-text-muted">{path}</div>
<Button variant="secondary" onClick={choose}>Choose…</Button>
</div>
</Field>Field props
| Prop | Type | |
|---|---|---|
children | ReactNode | Required. The control. |
label | ReactNode | Drawn as a SectionLabel above the control. |
hint | ReactNode | The line under the control that says what goes in it. |
error | ReactNode | Shown under the control and marks it invalid. null or '' shows nothing. |
group | boolean | Labels a group rather than one control. Default false. |
className | string | |
ref | Ref<HTMLDivElement> |
FieldHint and FormError
FieldHint is a <p> in the hint's style with a 4 pixel margin above it. FormError is a <p> with role="alert", so a screen reader announces it when it appears; use it for what went wrong in a dialog or a form as a whole. Both take className, ref and render.
FieldProps, FieldHintProps and FormErrorProps are exported types.