Skip to content
weftGitHub

Search

A text field for finding things, with a search icon and a clear button.

SourcePackage @weft-js/warpPlayground

Preview

tsx
import { Search, Stack } from '@weft-js/warp'export function Sizes() {  return (    <Stack gap="group">      <Search label="Search projects" size="sm" />      <Search label="Search projects" />      <Search label="Search projects" size="lg" />    </Stack>  )}

Installation

npm install @weft-js/warp

Usage

tsx
import { Search } from '@weft-js/warp'<Stack gap="group">  <Search label="Search projects" size="sm" />  <Search label="Search projects" />  <Search label="Search projects" size="lg" /></Stack>

Placeholder

Say what can be searched. The label still names the field.

tsx
import { Search, Stack } from '@weft-js/warp'export function Placeholder() {  return (    <Stack gap="group">      <Search label="Search projects" placeholder="Name, owner or region" />      <Search label="Search projects" variant="classic" placeholder="Name, owner or region" />    </Stack>  )}

States

A search field can show a hint or an error, and can be disabled or readonly.

tsx
import { Grid, Search, Stack, Text } from '@weft-js/warp'export function States() {  return (    <Grid cols={3} gap="group">      <Cell name="Empty"><Search label="Search projects" /></Cell>      <Cell name="Filled"><Search label="Search projects" defaultValue="checkout" /></Cell>      <Cell name="Hint"><Search label="Search projects" hint="Name, owner or region." /></Cell>      <Cell name="Invalid"><Search label="Search projects" defaultValue="region:" error="Finish the filter, like region:eu-west." /></Cell>      <Cell name="Disabled"><Search label="Search projects" defaultValue="checkout" disabled /></Cell>      <Cell name="Read-only"><Search label="Search projects" defaultValue="checkout" readonly /></Cell>    </Grid>  )}const Cell = (p: { name: string; children?: unknown }) => (  <Stack gap="tight">    <Text role="caption" subtle>{p.name}</Text>    {p.children}  </Stack>)

Filter a list

Try jun or eu-west.

tsx
import { derived, state } from '@weft-js/core'import { Row, Search, Stack, Text } from '@weft-js/warp'export function Projects() {  const q = state('')  const hits = derived(() => {    const s = q.value.trim().toLowerCase()    return PROJECTS.filter(p => `${p.name} ${p.owner} ${p.region}`.toLowerCase().includes(s)).slice(0, 5)  })  return (    <Stack gap="group">      <Search label="Search projects" placeholder="Name, owner or region" value={q.value} onInput={e => (q.value = e.currentTarget.value)} />      <Stack gap="tight">        {hits.value.map(p => <Row key={p.id} justify="between"><Text>{p.name}</Text><Text subtle>{p.region}</Text></Row>)}        {!hits.value.length && <Text subtle>Nothing matches “{q.value}”.</Text>}      </Stack>    </Stack>  )}type Status = 'Live' | 'Building' | 'Failed' | 'Paused'const PROJECTS: { id: string; name: string; owner: string; region: string; status: Status; deploys: number; uptime: number; latency: number; cost: number; updated: string }[] = [  { id: 'storefront', name: 'storefront', owner: 'Priya Raman', region: 'eu-west', status: 'Live', deploys: 412, uptime: 99.98, latency: 84, cost: 1240, updated: '2026-10-31' },  { id: 'checkout', name: 'checkout', owner: 'Tomás Oliveira', region: 'eu-west', status: 'Live', deploys: 288, uptime: 99.95, latency: 112, cost: 980, updated: '2026-10-31' },  { id: 'search-api', name: 'search-api', owner: 'Lena Fischer', region: 'us-east', status: 'Building', deploys: 196, uptime: 99.91, latency: 146, cost: 1610, updated: '2026-10-30' },  { id: 'billing', name: 'billing', owner: 'Mara Lindqvist', region: 'us-east', status: 'Live', deploys: 154, uptime: 99.99, latency: 73, cost: 720, updated: '2026-10-29' },  { id: 'mobile-bff', name: 'mobile-bff', owner: 'Sam Okafor', region: 'ap-south', status: 'Failed', deploys: 233, uptime: 99.42, latency: 208, cost: 860, updated: '2026-10-29' },  { id: 'notifier', name: 'notifier', owner: 'Jun Tanaka', region: 'eu-north', status: 'Live', deploys: 97, uptime: 99.97, latency: 58, cost: 310, updated: '2026-10-27' },  { id: 'reports', name: 'reports', owner: 'Noor Haddad', region: 'us-west', status: 'Paused', deploys: 41, uptime: 99.8, latency: 321, cost: 190, updated: '2026-10-22' },  { id: 'edge-cache', name: 'edge-cache', owner: 'Jun Tanaka', region: 'global', status: 'Live', deploys: 318, uptime: 100, latency: 21, cost: 1430, updated: '2026-10-31' },  { id: 'auth', name: 'auth', owner: 'Mara Lindqvist', region: 'eu-west', status: 'Live', deploys: 176, uptime: 99.99, latency: 66, cost: 540, updated: '2026-10-28' },  { id: 'ingest', name: 'ingest', owner: 'Lena Fischer', region: 'us-east', status: 'Live', deploys: 264, uptime: 99.93, latency: 131, cost: 2120, updated: '2026-10-30' },]

When to use

Use it for

  • Filtering a list as people type
  • Finding something across the app

Reach for something else

Playground

Size
import { Search } from '@weft-js/warp'<Search label="Search projects" placeholder="Name, owner or region" />

Accessibility

Esc
Clears the text
Enter
Submits its form
  • The field sits in a search landmark, so people can jump straight to it.
  • Announce the number of results in a live region when the list changes a lot.

API Reference

PropTypeDefaultDescription
labelstring—The name people read and screen readers announce. Always required, and it floats on the border by default.
hintunknown—A short line of help under the field.
errorunknown—Replaces the hint and marks the field invalid.
iconIconRef—Leading icon: it sweeps with the border.
prefixunknown—Text or an element inside the field before the value, such as $.
suffixunknown—Text or an element inside the field after the value, such as kg.
variant"floating" | "classic"—floating puts the label on the border, classic above the field.
appearance"line"—line draws only the bottom edge.
size"sm" | "md" | "lg"—sm, md or lg. Each follows the density around it.
clearablebooleanfalseA clear button (shown once there is a value).
counternumber—Maximum length, shown as a counter.
idstring—The element id. One is made for you if you leave it out.
valuestring—The current value, when you own the state.
disabledbooleanfalseCan't be focused or changed, and doesn't post with a form.
readonlybooleanfalseCan be focused, read and copied, but not changed. It still posts.
placeholderstring—What can be searched. Never the only label.
EventTypeDefaultDescription
onInput((e: InputEvent & { currentTarget: HTMLInputElement & HTMLTextAreaElemen…—Called on each keystroke.

Parts

Every element carries a stable name, so you can style it from your own CSS: [data-scope="search"] [data-part="input"]

input

RelatedInputCommand palette