Search field
A search field takes a search query. It has a search icon, a clear button, and a loading state. It doesn't search; you run the query and show the results.
<form action="/search"> <tk-search-field name="q" label="Search invoices" placeholder="Invoice number or customer"></tk-search-field> </form>
Anatomy
| Part | What it is |
|---|---|
tk-search-field |
the element; submits one value under name |
field part |
the bordered box |
| search icon | decorative; a spinner replaces it while loading |
input part |
the native <input type="search"> |
clear part |
the clear button; shows once there is text, and takes focus |
Label
<tk-search-field label="Search orders"></tk-search-field>
<tk-field label="Find a customer" helper="Name, email, or account ID"> <tk-search-field name="customer"></tk-search-field> </tk-field>
- A search field has no visible label. It names itself from
label, "Search" by default. Change it to say what is searched:label="Search orders". - For a visible label, help text, or an error, wrap it in a
Field . The Field's label then names it; don't also setlabel.
Sizes
<tk-search-field label="Search files"></tk-search-field> <tk-search-field label="Search files" size="large"></tk-search-field>
size |
Height | Padding-inline | Value text |
|---|---|---|---|
medium (default) |
32px | space-8 start, space-4 end |
Body Small (14/20) |
large |
36px | space-10 start, space-4 end |
Body Medium (16/24) |
The heights match medium and large buttons. There is no small; size="small"
renders as medium and logs a console warning.
States
<tk-search-field label="Search invoices" value="March" loading></tk-search-field> <tk-search-field label="Search invoices" disabled></tk-search-field>
The box doesn't change on hover. On focus in the text, its border takes the focus color and grows thicker inward; the clear button has its own focus ring.
loading: a spinner replaces the search icon, and the field tells screen readers it's busy. The clear button stays, so people can still cancel by clearing.disabled: the field can't be focused or edited, the clear button is hidden, and it's left out of the form.- Error and required: set
errorandrequiredon aField .
Clearing
- The clear button and Escape both empty the field. Focus moves to the text, so it's never lost.
- Escape only acts when there is text. In a
Dialog orPopover , the first Escape clears the field and the next one closes the overlay. - A clear fires
input,change, andtk-clear.tk-clearsays how:detail.reasonisbuttonorescape. You can't cancel it.
Running the search
The field holds the query. You decide when to search, how long to wait, and how to tell people what you found:
<tk-search-field id="filter" label="Filter sections"></tk-search-field>
<p id="count" role="status"></p>
<script>
const field = document.getElementById('filter');
field.addEventListener('input', debounce(() => render(field.value), 200));
field.addEventListener('tk-clear', () => render(''));
</script>- Listen for
inputwhile people type,changewhen they commit, or the form'ssubmiton Enter. - There is no built-in delay; wait as long as your search needs.
- Announce the result count in your own
role="status"region, such as "12 results".
When to use
- Use a search field for a query that filters or fetches something shown elsewhere on the page: a list, a table, a results page.
- Use an
Input for any other single-line value, such as a name or a URL. - Use a
Combobox instead when the query must end on one option from a list, such as with suggestions or autocomplete. Don't put a Combobox inside a search field. - Put a submit button next to the field, not inside it.
| Search field | Combobox | |
|---|---|---|
| Enter | submits the query as typed | picks the highlighted option |
| The value | free text | one of the options |
| The results | elsewhere on the page, yours | in its own list |
Content
label: say what is searched: "Search invoices", not just "Search".- Placeholder: optional; a short hint of what people can type, such as "Invoice number or customer". Never the only description.
clear-label: "Clear search" by default; change it iflabelis in another language.
Do / Don't
| ✅ Do | ❌ Don't |
|---|---|
Put the field in a <form> so Enter submits |
Write your own Enter handler to submit |
Say what is searched in label |
Leave three fields on a page all named "Search" |
Announce results in your own role="status" |
Expect the field to announce results |
| Use a Combobox when the query picks an option | Nest a Combobox in a search field |
| Delay your own queries as long as they need | Look for a debounce attribute |
Related
Input : any other single-line value.Combobox : a query that picks one option from a list.Field : a visible label, help text, and error around the field.
API
Attributes
| Attribute | Type | Default | What it does |
|---|---|---|---|
value |
string | '' |
the query; updates as people type; setting it fires no event |
name |
string | — | the form field name |
label |
string | 'Search' |
the accessible name; not shown; ignored inside a Field |
placeholder |
string | — | hint text shown while empty |
clear-label |
string | 'Clear search' |
the clear button's accessible name |
loading |
boolean | false |
spinner in place of the search icon, and aria-busy |
size |
medium | large |
medium |
height 32 / 36px |
disabled |
boolean | false |
not focusable, not editable, left out of the form |
required |
boolean | false |
the browser blocks submitting while empty |
Events
| Event | Detail | When |
|---|---|---|
input |
— | on every keystroke and every clear |
change |
— | when the query is committed, on blur or Enter, and on every clear |
tk-clear |
{ reason: 'button' | 'escape' } |
after the clear button or Escape empties the field; not cancelable |
Methods
focus(): moves focus to the text.
CSS
::part(field): the bordered box.::part(input): the native<input>.::part(clear): the clear button.
Tokens
The box uses the
| Role | Token |
|---|---|
| search icon and spinner | icon/secondary; icon/disabled when disabled |
| clear icon | icon/default |
| clear button hover / press | state/hover / state/press |
| clear button focus ring | border/accent/focus, drawn inside the button |
The clear button is a 24×24 circle (radius-full) with a 16px icon. Values per theme:
Accessibility
Built in:
- A native search input with the
searchboxrole. - The clear button is a real button with a name: Tab reaches it, Space and Enter clear.
- Focus never drops to the page when the field clears.
- Escape never gets stuck: on an empty field it passes through.
- The browser's own clear button is hidden, so there is only one.
- The search icon and spinner are hidden from screen readers.
Your part:
- Name the field for what it searches, with
labelor a Field. - Announce results in your own live region; the field can't know them.
| Key | Action |
|---|---|
Tab |
moves to the text, then to the clear button when there is text |
Enter |
submits the form |
Escape |
clears the field; does nothing when it's empty |
Space / Enter on the clear button |
clears the field and returns focus to the text |
Contrast limits
The box shares the Input's limits: see