componentId | title | status | description | source | storybook |
---|---|---|---|---|---|
inputField |
InputField |
Alpha |
The InputField component is used to render a labelled text input and, optionally, associated validation text and hint text. |
/react/storybook?path=/story/forms-inputfield--text-input-field |
import {InputField, TextInputWithTokens, Autocomplete, Select} from '@primer/react'
<InputField>
<InputField.Label>Name</InputField.Label>
<TextInput />
</InputField>
<InputField required>
<InputField.Label>Name</InputField.Label>
<TextInput />
</InputField>
<InputField disabled>
<InputField.Label>Name</InputField.Label>
<TextInput />
</InputField>
const TextInputWithTokensExample = () => {
const [tokens, setTokens] = React.useState([
{text: 'zero', id: 0},
{text: 'one', id: 1},
{text: 'two', id: 2}
])
const onTokenRemove = tokenId => {
setTokens(tokens.filter(token => token.id !== tokenId))
}
return (
<Box
display="flex"
flexDirection="column"
sx={{
'> * + *': {
marginTop: 4
}
}}
>
<InputField>
<InputField.Label>TextInputWithTokens</InputField.Label>
<TextInputWithTokens onTokenRemove={onTokenRemove} tokens={tokens} />
</InputField>
<InputField>
<InputField.Label>Autocomplete</InputField.Label>
<Autocomplete>
<Autocomplete.Input block />
<Autocomplete.Overlay>
<Autocomplete.Menu
items={[
{text: 'css', id: 0},
{text: 'css-in-js', id: 1},
{text: 'styled-system', id: 2},
{text: 'javascript', id: 3},
{text: 'typescript', id: 4},
{text: 'react', id: 5},
{text: 'design-systems', id: 6}
]}
selectedItemIds={[]}
/>
</Autocomplete.Overlay>
</Autocomplete>
</InputField>
<InputField>
<InputField.Label>Select</InputField.Label>
<Select>
<Select.Option value="figma">Figma</Select.Option>
<Select.Option value="css">Primer CSS</Select.Option>
<Select.Option value="prc">Primer React components</Select.Option>
<Select.Option value="pvc">Primer ViewComponents</Select.Option>
</Select>
</InputField>
</Box>
)
}
render(TextInputWithTokensExample)
With a visually hidden label
Every input must have a corresponding label to be accessible to assistive technology. That's why you'd use InputField
instead of using TextInput
directly.
InputField
also provides an interface for showing a hint text caption and a validation message, and associating those with the input for assistive technology.
<InputField>
<InputField.Label visuallyHidden>Name</InputField.Label>
<TextInput />
</InputField>
<InputField>
<InputField.Label>Name</InputField.Label>
<TextInput />
<InputField.Caption>Hint: your first name</InputField.Caption>
</InputField>
const ValidationExample = () => {
const [value, setValue] = React.useState('mona lisa')
const [validationResult, setValidationResult] = React.useState()
const doesValueContainSpaces = inputValue => /\s/g.test(inputValue)
const handleInputChange = e => {
setValue(e.currentTarget.value)
}
React.useEffect(() => {
if (doesValueContainSpaces(value)) {
setValidationResult('noSpaces')
} else if (value) {
setValidationResult('validName')
}
}, [value])
return (
<InputField
validationMap={{
noSpaces: 'error',
validName: 'success'
}}
validationResult={validationResult}
>
<InputField.Label>GitHub handle</InputField.Label>
<TextInput block value={value} onChange={handleInputChange} />
<InputField.Validation validationKey="noSpaces">GitHub handles cannot contain spaces</InputField.Validation>
<InputField.Validation validationKey="validName">Valid name</InputField.Validation>
<InputField.Caption>With or without "@". For example "monalisa" or "@monalisa"</InputField.Caption>
</InputField>
)
}
render(ValidationExample)
The container that handles the layout and passes the relevant IDs and ARIA attributes it's children.
A InputField.Label
must be passed for the field to be accessible to assistive technology, but it may be visually hidden.
InputField.Caption
may be used to render hint text for fields that require additional context.
InputField.Validation
may be used to render contextual validation information if the field was flagged during validation.
<ComponentChecklist items={{ propsDocumented: true, noUnnecessaryDeps: true, adaptsToThemes: true, adaptsToScreenSizes: true, fullTestCoverage: true, usedInProduction: false, usageExamplesDocumented: true, designReviewed: false, a11yReviewed: true, stableApi: false, addressedApiFeedback: false, hasDesignGuidelines: false, hasFigmaComponent: false }} />