Search Field
A search input with a search icon and a clear button, which clears with Escape and reports Enter.
Overview
SearchField is a native <input type="search">, built on React Aria's useSearchField. It
renders chassis-css's input adorn shape: a
.form-input around the input, with a search icon at its start and, while there is a value, a
button that clears it.
Like the other form fields, it takes label, help and the validation props, and renders a
FormLabel, FormHelp and FormFeedback wired to it.
import { SearchField } from '@chassis-ui/react'
export const Example = () => (
<SearchField help="Pages and posts." label="Search" placeholder="Search…" />
)The field takes chassis-css's sizes and states. Its own styles, which hide the browser's clear
button and color the clear button by the field's state, are in @chassis-ui/react/style.css (see
Theming).
Value
Pass value and onChange to control the value, or defaultValue to let the component manage
it. The clear button and the Escape key empty the field, keep focus on the input and call
onClear; Escape in an empty field does nothing, so it reaches a dialog or menu around the field.
An onKeyDown given to the field stops every key there, as in React Aria, unless it calls
event.continuePropagation().
- Apple
- Apricot
- Banana
- Blackberry
- Cherry
- Grape
- Mango
- Peach
import { useState } from 'react'
import { List, ListItem, SearchField, Stack } from '@chassis-ui/react'
const fruits = ['Apple', 'Apricot', 'Banana', 'Blackberry', 'Cherry', 'Grape', 'Mango', 'Peach']
export const Example = () => {
const [query, setQuery] = useState('')
const matches = fruits.filter((fruit) => fruit.toLowerCase().includes(query.toLowerCase()))
return (
<Stack direction="vertical" gap="md" style={{ maxWidth: '20rem' }}>
<SearchField label="Filter fruits" onChange={setQuery} value={query} />
<List>
{matches.map((fruit) => (
<ListItem key={fruit}>{fruit}</ListItem>
))}
{matches.length === 0 && <ListItem>No fruit matches “{query}”.</ListItem>}
</List>
</Stack>
)
}Submitting
onSubmit receives the value when Enter is pressed, with or without a modifier key and in a
read-only field too. With it, Enter no longer submits the input's form: use it for a search that
runs in place.
import { useState } from 'react'
import { SearchField } from '@chassis-ui/react'
export const Example = () => {
const [searched, setSearched] = useState('')
return (
<SearchField
help={searched ? `Searched for “${searched}”.` : 'Press Enter to search.'}
label="Search"
onClear={() => setSearched('')}
onSubmit={setSearched}
/>
)
}In a form
Without onSubmit, Enter submits the form as in any text input, and with name the value is
submitted under that name. Resetting the form restores defaultValue.
import { useState } from 'react'
import { Button, SearchField, Stack } from '@chassis-ui/react'
export const Example = () => {
const [submitted, setSubmitted] = useState('')
return (
<form
onSubmit={(event) => {
event.preventDefault()
setSubmitted(JSON.stringify(Object.fromEntries(new FormData(event.currentTarget))))
}}
>
<Stack direction="vertical" gap="md" style={{ maxWidth: '20rem' }}>
<SearchField
help={submitted ? `Submitted: ${submitted}` : undefined}
label="Search"
name="q"
/>
<Button type="submit">Search</Button>
</Stack>
</form>
)
}Icons
searchIcon and clearIcon replace the two icons, by name or as an element; searchIcon={false}
leaves the search icon out. To replace them everywhere, map search and clear in
IconProvider's icons.
import { SearchField } from '@chassis-ui/react'
export const Example = () => (
<>
<SearchField aria-label="Without the search icon" defaultValue="chassis" searchIcon={false} />
<SearchField
aria-label="Other icons"
clearIcon="xmark-circle-solid"
defaultValue="chassis"
searchIcon="search-solid"
/>
</>
)Sizing
import { SearchField } from '@chassis-ui/react'
export const Example = () => (
<>
<SearchField aria-label="Small" defaultValue="chassis" size="sm" />
<SearchField aria-label="Medium" defaultValue="chassis" />
<SearchField aria-label="Large" defaultValue="chassis" size="lg" />
</>
)States
disabled and readOnly keep the value from changing, and leave the clear button out. invalid
and valid color the field and show invalidFeedback or validFeedback.
import { SearchField } from '@chassis-ui/react'
export const Example = () => (
<>
<SearchField defaultValue="chassis" disabled label="Disabled" />
<SearchField defaultValue="chassis" label="Read only" readOnly />
<SearchField
defaultValue="c"
invalid
invalidFeedback="Type at least two letters."
label="Invalid"
/>
<SearchField defaultValue="chassis" label="Valid" valid validFeedback="12 results." />
</>
)Accessibility
The input has the searchbox role and is named by its label; give it an aria-label when there is
no visible one. The search icon is hidden from assistive technology. The clear button is named
"Clear search" in the locale's language, or by clearAriaLabel, and is left out of the tab order,
since Escape does the same from the input.
API
SearchField
| Prop | Type | Default |
|---|---|---|
className? | string | — |
| A string of all className you want applied to the component. | ||
clearAriaLabel? | string | — |
| The accessible name of the clear button. Defaults to react-aria's, in the locale's language ("Clear search"). | ||
clearIcon? | IconValue | — |
The icon of the clear button, in place of IconProvider's clear icon. | ||
defaultValue? | string | — |
| The value of the field, uncontrolled. | ||
disabled? | boolean | — |
| Toggle the disabled state for the component. | ||
help? | ReactNode | — |
| A description for the field, rendered below it. | ||
invalid? | boolean | — |
Set component validation state to invalid. Left unset, the component shows as invalid by itself
from a submit it held back (an empty required one, say) until it no longer would, or its
form is reset. Set it, to false too, and it alone decides. | ||
invalidFeedback? | ReactNode | — |
An error message for the field, rendered below it when invalid is set, and after a submit
the field held back, until it no longer would. | ||
label? | ReactNode | — |
The field's caption, rendered as a FormLabel associated with the input. | ||
onChange? | ((value: string) => void) | — |
| Handler that is called when the value changes. | ||
onClear? | (() => void) | — |
| Handler that is called when the field is cleared, by the clear button or the Escape key. | ||
onSubmit? | ((value: string) => void) | — |
| Handler that is called when the Enter key is pressed, with the value. When set, Enter, with or without a modifier key, no longer submits the input's form. | ||
readOnly? | boolean | — |
| Toggle the readonly state for the component. | ||
searchIcon? | false | IconValue | — |
The icon at the field's start, in place of IconProvider's search icon. false leaves it
out. | ||
size? | "sm" | "lg" | — |
| Size the component sm or lg. | ||
valid? | boolean | — |
| Set component validation state to valid. | ||
validFeedback? | ReactNode | — |
A success message for the field, rendered below it when valid is set. | ||
value? | string | — |
| The value of the field, controlled. | ||