A pattern for this page also exists
For how to arrange a Form, including the components use to build one, refer
to the pattern page on Forms.
<State initial={false}>
{([organization, setOrganization]) => (
<Form>
<Headline el="div" className="m-b-4">
Add Contact
</Headline>
<Form.Group widths="equal" className="m-b-3">
<Form.Input label="First Name" placeholder="Leia" />
<Form.Input label="Last Name" placeholder="Organa" />
</Form.Group>
<Form.AnvilSelect
label="Home Planet"
trigger={{
placeholder: 'Choose Planet',
}}
className="m-b-3"
options={[
{ key: 1, value: 1, text: 'Alderaan' },
{ key: 2, value: 2, text: 'Bespin' },
{ key: 3, value: 3, text: 'Coruscant' },
{ key: 4, value: 4, text: 'Dagobah' },
{ key: 5, value: 5, text: 'Hoth' },
{ key: 6, value: 6, text: 'Kashyyyk' },
{ key: 7, value: 7, text: 'Naboo' },
{ key: 8, value: 8, text: 'Tatooine' },
{ key: 9, value: 9, text: 'Yavin' },
]}
/>
<Form.Field className="m-b-3">
<Grid columns="equal">
<Grid.Column>
<Form.Group grouped>
<label>Organization</label>
<Form.Radio
label="Rebel Alliance"
value="1"
checked={organization === 1}
onChange={() => setOrganization(1)}
/>
<Form.Radio
label="Galactic Empire"
value="2"
checked={organization === 2}
onChange={() => setOrganization(2)}
/>
<Form.Radio
label="Trade Federation"
value="3"
checked={organization === 3}
onChange={() => setOrganization(3)}
/>
</Form.Group>
</Grid.Column>
<Grid.Column>
<Form.Group grouped>
<label>Attributes</label>
<Form.Checkbox label="Force User" />
<Form.Checkbox label="Pilot" />
<Form.Checkbox label="Bounty Hunter" />
</Form.Group>
</Grid.Column>
</Grid>
</Form.Field>
<Form.TextArea
label="Quotes"
showCounter
maxLength={300}
placeholder="Aren't you a little short for a stormtrooper?"
className="m-b-3"
/>
<Form.Group className="m-t-5">
<Form.Button primary>Save Contact</Form.Button>
<Form.Button>Cancel</Form.Button>
</Form.Group>
</Form>
)}
</State>
Form.Group with widths="equal" and long descriptions
To fix a known formatting issue in Form.Groups
with widths="equal"
and long descriptions or error text, add this CSS to any relevant form input elements to ensure they always maintain equal widths:
flex-basis: min-content
Labels
Components within a Form have a few labeling options.
<Form>
<Form.Input label="Input Label" />
</Form>
<Form>
<Form.Checkbox label="Checkbox Label" />
<Form.Radio label="Radio Label" />
</Form>
<Form>
<Form.AnvilSelect label="Select Label" options={[]} />
</Form>
Label Help
Labels can have a help icon with a tooltip to provide additional context to a label.
<Form>
<Form.Input
label="Input Label"
labelProps={{
help: 'This is help text',
}}
/>
</Form>
<Form>
<Form.Checkbox
label="Checkbox Label"
labelProps={{
help: 'This is help text',
}}
/>
<Form.Radio
label="Radio Label"
labelProps={{
help: 'This is help text',
}}
/>
</Form>
<Form>
<Form.AnvilSelect
label="Select Label"
labelProps={{
help: 'The tooltip direction can also be controlled',
direction: 'b',
}}
options={[]}
/>
</Form>
Required and Optional
A visual indicator can be applied on a form's label. Refer to the pattern for suggested use.
<Form>
<Form.Input
label="Required Label"
labelProps={{
required: true,
}}
/>
<Form.Input
label="Required Label"
labelProps={{
help: 'Help and required next to each other',
required: true,
}}
/>
</Form>
<Form>
<Form.Input
label="Optional Label"
labelProps={{
optional: true,
}}
/>
<Form.Input
label="Optional Label"
labelProps={{
help: 'Help and optional next to each other',
optional: true,
}}
/>
</Form>
Label Action
An action can be applied to certain forms. This action is a closely related secondary option to the field.
<Form>
<Form.Input
label="Field Label"
labelProps={{
action: (
<Link primary onClick={() => alert('Label action triggered')}>
Label Action
</Link>
),
}}
/>
</Form>
<State initial={false}>
{([open, setOpen]) => (
<Form>
<Form.Input
label="Field Label"
labelProps={{
action: (
<Stack justifyContent="center">
<Popover
header={
<BodyText size="small">
Popover Header
</BodyText>
}
headerAlign="space-between"
trigger={
<Link
primary
onClick={() => setOpen(!open)}
>
Popover Action
</Link>
}
footer={
<BodyText size="small">
Popover Footer
</BodyText>
}
open={open}
direction="tl"
width="xs"
>
<div>
<BodyText size="small">
Popover content.
</BodyText>
<BodyText size="small">
Second line of text.
</BodyText>
</div>
</Popover>
</Stack>
),
}}
/>
</Form>
)}
</State>
<State initial={false}>
{([open, setOpen]) => (
<div>
<Modal
closable
onClose={() => setOpen(false)}
open={open}
title="Accept Estimate"
footer={
<Button primary onClick={() => setOpen(false)}>
Submit
</Button>
}
>
This is a modal that was triggered by an action.
</Modal>
<Form>
<Form.Input
label="Field Label"
labelProps={{
action: (
<Link primary onClick={() => setOpen(true)}>
Modal Action
</Link>
),
}}
/>
</Form>
</div>
)}
</State>
<State initial={false}>
{([open, setOpen]) => (
<div>
<Drawer
header="Drawer Header"
open={open}
onClose={() => setOpen(false)}
>
Content related to the field.
</Drawer>
<Form>
<Form.Input
label="Field Label"
labelProps={{
action: (
<Link primary onClick={() => setOpen(!open)}>
Drawer Action
</Link>
),
}}
/>
</Form>
</div>
)}
</State>
Counter
Counter can be displayed for Input and TextArea when there is a maxLength
.
<Form>
<Form.Input label="Counter Example" maxLength={20} showCounter />
<Form.TextArea label="Counter Example" maxLength={200} showCounter />
</Form>
Errors
Forms can provide a visual for errors.
<Form
style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gridRowGap: '16px',
gridColumnGap: '16px',
justifyItems: 'stretch',
alignItems: 'start',
}}
>
<Form.Input
label="Input Label"
value="Input value"
error="This is error text"
/>
<Form.AnvilSelect
label="Select Label"
placeholder="Select value"
error="This is error text"
options={[]}
/>
<Form.Radio
label="Field Label"
value="Input value"
error="This is error text"
/>
<Form.Checkbox
label="Field Label"
value="Input value"
error="This is error text"
/>
</Form>
<Form>
<Form.Input
label="Input Label"
value="Input value"
error={
<Stack className="m-t-2" alignItems="flex-start">
<Icon name="warning" size={18} className="c-red-500 m-r-1" />
<Stack direction="column">
<BodyText className="c-red-500 m-b-1 lh-1" size="small">
{' '}
This is a custom made error message
</BodyText>
<BodyText className="c-red-500 lh-1" size="small">
This is a second line of errors
</BodyText>
</Stack>
</Stack>
}
/>
</Form>
Field Descriptions
A form can also have description content below the control. This content can be useful to provide context to the user.
<Form
style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gridRowGap: '24px',
gridColumnGap: '24px',
justifyItems: 'stretch',
alignItems: 'start',
}}
>
<Form.Input
label="Name"
value="John Doe"
description="Your name may appear around the site."
/>
<Form.Input
label="Password"
type="Password"
value="123456"
description={
<React.Fragment>
<BodyText subdued size="small" className="m-t-2 m-b-half">
Use 8 or more characters
</BodyText>
<BodyText subdued size="small" className="m-b-half">
Use at least one uppercase and one lowercase letter (Aa)
</BodyText>
<BodyText subdued size="small">
Use at least one digit (0-9)
</BodyText>
</React.Fragment>
}
/>
<Form.ToggleSwitch
label="Show Job History"
placeholder="Select value"
description="Enabling this will show job information to everyone who has access to project history."
/>
<Form.Checkbox
label="XLS"
size="large"
description="Only supports version X, Y, and Z."
/>
<Form.Input
label="Description and Error"
value="Input Value"
description="Description text in relation to error text"
error="This is an error message"
/>
</Form>
Related Content
Components
Patterns
Importing
import { Form } from '@servicetitan/design-system';