- Accordion
- Action Bar
- Action Toast
- Alert Banner
- Alert Dialog
- Alert
- Alphabet Index
- Amount Field
- Aspect Ratio
- Attachment
- Availability List
- Avatar
- Badge
- Bank Card
- Breadcrumb
- Bubble
- Button Group
- Button
- Calendar
- Camera Frame
- Card Design Picker
- Card Details
- Card Peek
- Card Stack
- Card
- Carousel
- Chart
- Chat Thread
- Checkbox
- Chip Group
- Choice Tile
- Code Block
- Code Dots
- Collapsible
- Combobox
- Command
- Context Menu
- Copy Field
- Countdown
- Country Select
- Data Table
- Date Field
- Date Picker
- Date Range Picker
- Dialog
- Direction
- Document Paper
- Drawer
- Dropdown Menu
- Empty
- Entity Avatar
- Field
- File Trigger
- File Upload Item
- Hover Card
- Input Group
- Input OTP
- Input
- Item
- Kbd
- Key Value
- Keypad
- Label
- Live Region
- Marker
- Message Scroller
- Message
- Money Amount
- Native Select
- Number Field
- Pagination
- Percent Split Editor
- Phone Field
- Popover
- Progress
- QR Code
- Questionnaire
- Radio Group
- Range Histogram
- Rating
- Resizable
- Scroll Area
- Search Field
- Select
- Separator
- Share Bar
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Sortable List
- Spinner
- Status Timeline
- Step Header
- Steps List
- Swipe Row
- Switch
- Table
- Tabs
- Text Field
- Textarea
- Tier Ladder
- Toggle Group
- Toggle
- Token Search Field
- Tooltip
- Trace
- Transaction Row
- Usage Meter
"use client"
import {The TokenSearchField component is a search input for lists such as payment history, where people narrow results with filters. Typing a known operator such as from:maya and pressing Space or Enter turns it into a token, and free text stays editable after the tokens. Use it when filters are part of the query. For a plain text search, use a search field; for a fixed set of filters, use chips or a select next to it.
Installation#
pnpm dlx shadcn@latest add @dots/token-search-field
Usage#
import {
TokenSearchField,
type SearchOperator,
} from "@/components/ui/token-search-field"const operators: SearchOperator[] = [
{ key: "from", label: "From" },
{ key: "is", label: "Status" },
]
<TokenSearchField label="Search payments" operators={operators} />Features#
- Typed operators become tokens on Space or Enter when the caret is at the end
- Backspace at the start of the input moves to the last token, a second Backspace removes it
- Arrow keys move between tokens; Escape, typing, or the arrow past the last token returns to the input
- A clear button that removes the text and all tokens
- Controlled or uncontrolled tokens and text, and an
onSubmitwith both - Tokens added from outside, including plain text tokens with no operator
- Polite announcements when tokens are added, removed or cleared
Operators#
Pass operators to list what the user can type before a colon. Only known operators turn into tokens; amount:5 stays text if amount is not listed.
Type from:maya and press Space. Backspace at the start selects the last filter, a second Backspace removes it.
"use client"
import {Controlled#
Pass tokens with onTokensChange and value with onChange to own the query. onSubmit runs on Enter when there is no operator to finish and receives { text, tokens }.
Press Enter to search.
"use client"
import * as React from "react"Filters from outside#
Add tokens from your own controls, such as suggestion chips. A token without operator shows its value only.
"use client"
import * as React from "react"Disabled#
Set isDisabled to lock the input and the tokens. The clear and remove buttons are hidden.
"use client"
import {Accessibility#
TokenSearchField is built on React Aria SearchField and TagGroup. The input gets search semantics, Escape clears it, and the tokens are a grid of tags you move through with the arrow keys and remove with Backspace or Delete.
Label the field#
Pass label for a visible label. Without one, pass aria-label.
<TokenSearchField aria-label="Search payments" operators={operators} />Labels for the parts#
tokensLabel names the list of tokens, removeLabel starts the name of each remove button, and clearLabel names the clear button. Each remove button is named after its token, such as "Remove Status pending". Translate all three with the rest of your UI.
Announcements#
A hidden live region says "Added", "Removed" or "Cleared filters" so screen reader users hear changes that happen without a focus move.
API Reference#
TokenSearchField#
Accepts all React Aria SearchField props except children, className, onSubmit, value, defaultValue and onChange, which are replaced below.
| Prop | Type | Default | Description |
|---|---|---|---|
operators | SearchOperator[] | [] | Operators that turn key:value into a token. |
tokens | SearchToken[] | - | Finished filters (controlled). |
defaultTokens | SearchToken[] | [] | Finished filters (uncontrolled). |
onTokensChange | (tokens: SearchToken[]) => void | - | Called when tokens are added or removed. |
value | string | - | Free text after the tokens (controlled). |
defaultValue | string | "" | Free text after the tokens (uncontrolled). |
onChange | (value: string) => void | - | Called when the free text changes. |
onSubmit | (query: { text: string; tokens: SearchToken[] }) => void | - | Called on Enter when there is no operator to finish. |
label | ReactNode | - | Visible label. Without it, pass aria-label. |
placeholder | string | "Search" | Shown only while there are no tokens. |
tokensLabel | string | "Filters" | Names the list of tokens for screen readers. |
removeLabel | string | "Remove" | Start of each remove button's name. |
clearLabel | string | "Clear search" | Name of the clear button. |
isDisabled | boolean | - | Disables the input and the tokens. |
className | string | - | Additional classes to apply to the root element. |
SearchToken#
| Field | Type | Description |
|---|---|---|
id | string | Unique key for the token. |
operator | string | Operator key, such as "from". Omit for plain text. |
value | string | The filter value, such as "pending". |
SearchOperator#
| Field | Type | Description |
|---|---|---|
key | string | What the user types before the colon, such as "from". |
label | string | Quiet name shown on the token, such as "From". |