Skip to content
Lenso UI

SearchField

Search input field with clear button and search icon

Usage

import { SearchField } from '@lenso/ui';
"use client";
// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, SearchField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ input: { width: 280 } });
export function Basic() {  return (    <SearchField name="search">      <Label>Search</Label>      <SearchField.Group>        <SearchField.SearchIcon />        <SearchField.Input xstyle={styles.input} placeholder="Search..." />        <SearchField.ClearButton />      </SearchField.Group>    </SearchField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Anatomy

import {SearchField, Label, Description, FieldError} from '@lenso/ui';
export default () => (  <SearchField>    <Label />    <SearchField.Group>      <SearchField.SearchIcon />      <SearchField.Input />      <SearchField.ClearButton />    </SearchField.Group>    <Description />    <FieldError />  </SearchField>)

SearchField allows users to enter and clear a search query. It includes a search icon and an optional clear button for easy reset.

Examples

Variants

The SearchField component supports two visual variants:

  • primary (default) - Standard styling with shadow, suitable for most use cases
  • secondary - Lower emphasis variant without shadow, suitable for use in Surface components
"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, SearchField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", flexDirection: "column", gap: 16 },  input: { width: 280 },});export function Variants() {  return (    <div {...stylex.props(styles.root)}>      <SearchField name="primary-search" variant="primary">        <Label>Primary variant</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input xstyle={styles.input} placeholder="Search..." />          <SearchField.ClearButton />        </SearchField.Group>      </SearchField>      <SearchField name="secondary-search" variant="secondary">        <Label>Secondary variant</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input xstyle={styles.input} placeholder="Search..." />          <SearchField.ClearButton />        </SearchField.Group>      </SearchField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

In Surface

When used inside a Surface component, use variant="secondary" to apply the lower emphasis variant suitable for surface backgrounds.

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, SearchField, Surface } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: {    display: "flex",    width: "100%",    maxWidth: 384,    flexDirection: "column",    gap: 16,    borderRadius: 24,    padding: 24,  },  input: { width: "100%" },});export function OnSurface() {  return (    <Surface xstyle={styles.root}>      <SearchField name="search" variant="secondary">        <Label>Search</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input xstyle={styles.input} placeholder="Search..." />          <SearchField.ClearButton />        </SearchField.Group>        <Description>Enter keywords to search</Description>      </SearchField>      <SearchField name="search-2" variant="secondary">        <Label>Advanced search</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input xstyle={styles.input} placeholder="Advanced search..." />          <SearchField.ClearButton />        </SearchField.Group>        <Description>Use filters to refine your search</Description>      </SearchField>    </Surface>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

With Description

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, SearchField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", flexDirection: "column", gap: 16 },  input: { width: 280 },});export function WithDescription() {  return (    <div {...stylex.props(styles.root)}>      <SearchField name="search">        <Label>Search products</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input xstyle={styles.input} placeholder="Search products..." />          <SearchField.ClearButton />        </SearchField.Group>        <Description>Enter keywords to search for products</Description>      </SearchField>      <SearchField name="search-users">        <Label>Search users</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input xstyle={styles.input} placeholder="Search users..." />          <SearchField.ClearButton />        </SearchField.Group>        <Description>Search by name, email, or username</Description>      </SearchField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Required Field

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, SearchField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", flexDirection: "column", gap: 16 },  input: { width: 280 },});export function Required() {  return (    <div {...stylex.props(styles.root)}>      <SearchField name="search">        <Label>Search</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input required xstyle={styles.input} placeholder="Search..." />          <SearchField.ClearButton />        </SearchField.Group>      </SearchField>      <SearchField name="search-query">        <Label>Search query</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input required xstyle={styles.input} placeholder="Enter search query..." />          <SearchField.ClearButton />        </SearchField.Group>        <Description>Minimum 3 characters required</Description>      </SearchField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Disabled State

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, SearchField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", flexDirection: "column", gap: 16 },  input: { width: 280 },});export function Disabled() {  return (    <div {...stylex.props(styles.root)}>      <SearchField disabled name="search">        <Label>Search</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input            xstyle={styles.input}            value="Disabled search"            placeholder="Search..."          />          <SearchField.ClearButton />        </SearchField.Group>        <Description>This search field is disabled</Description>      </SearchField>      <SearchField disabled name="search-empty">        <Label>Search</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input xstyle={styles.input} placeholder="Search..." />          <SearchField.ClearButton />        </SearchField.Group>        <Description>This search field is disabled</Description>      </SearchField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Full Width

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, SearchField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ root: { width: 400 } });export function FullWidth() {  return (    <div {...stylex.props(styles.root)}>      <SearchField fullWidth name="search">        <Label>Search</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input placeholder="Search..." />          <SearchField.ClearButton />        </SearchField.Group>      </SearchField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Validation

Use isInvalid together with FieldError to surface validation messages.

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { FieldError, Label, SearchField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", flexDirection: "column", gap: 16 },  input: { width: 280 },});export function Validation() {  return (    <div {...stylex.props(styles.root)}>      <SearchField invalid name="search">        <Label>Search</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input required value="ab" xstyle={styles.input} placeholder="Search..." />          <SearchField.ClearButton />        </SearchField.Group>        <FieldError match>Search query must be at least 3 characters</FieldError>      </SearchField>      <SearchField invalid name="search-invalid">        <Label>Search</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input xstyle={styles.input} placeholder="Search..." value="invalid@query" />          <SearchField.ClearButton />        </SearchField.Group>        <FieldError match>Invalid characters in search query</FieldError>      </SearchField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Controlled

Control the value to synchronize with other components or perform custom formatting.

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Button, Description, Label, SearchField } from "@lenso/ui";import * as React from "react";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", flexDirection: "column", gap: 16 },  actions: { display: "flex", gap: 8 },  input: { width: 280 },});export function Controlled() {  const [value, setValue] = React.useState("");  return (    <div {...stylex.props(styles.root)}>      <SearchField name="search">        <Label>Search</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input            xstyle={styles.input}            placeholder="Search..."            value={value}            onValueChange={setValue}          />          <SearchField.ClearButton />        </SearchField.Group>        <Description>Current value: {value || "(empty)"}</Description>      </SearchField>      <div {...stylex.props(styles.actions)}>        <Button variant="tertiary" onClick={() => setValue("")}>          Clear        </Button>        <Button variant="tertiary" onClick={() => setValue("example query")}>          Set example        </Button>      </div>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Form Example

Complete form integration with validation and submission handling.

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Button, Description, FieldError, Form, Label, SearchField, Spinner } from "@lenso/ui";import * as React from "react";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", width: 280, flexDirection: "column", gap: 16 },  full: { width: "100%" },});export function FormExample() {  const [value, setValue] = React.useState("");  const [isSubmitting, setIsSubmitting] = React.useState(false);  const timer = React.useRef<ReturnType<typeof setTimeout> | null>(null);  React.useEffect(    () => () => {      if (timer.current) clearTimeout(timer.current);    },    [],  );  const MIN_LENGTH = 3;  const isInvalid = value.length > 0 && value.length < MIN_LENGTH;  const handleSubmit = (event: React.FormEvent) => {    event.preventDefault();    if (value.length < MIN_LENGTH || isSubmitting) return;    setIsSubmitting(true);    timer.current = setTimeout(() => {      console.log("Search submitted:", { query: value });      setValue("");      setIsSubmitting(false);    }, 1500);  };  return (    <Form xstyle={styles.root} onSubmit={handleSubmit}>      <SearchField invalid={isInvalid} name="search">        <Label>Search products</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input            required            xstyle={styles.full}            placeholder="Search products..."            value={value}            onValueChange={setValue}          />          <SearchField.ClearButton />        </SearchField.Group>        {isInvalid ? (          <FieldError match>Search query must be at least {MIN_LENGTH} characters</FieldError>        ) : (          <Description style={{ display: "block" }}>            Enter at least {MIN_LENGTH} characters to search          </Description>        )}      </SearchField>      <Button        xstyle={styles.full}        disabled={value.length < MIN_LENGTH}        isLoading={isSubmitting}        type="submit"        variant="primary"      >        {isSubmitting ? (          <>            <Spinner color="current" size="sm" />            Searching...          </>        ) : (          "Search"        )}      </Button>    </Form>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

With Validation

Implement custom validation logic with controlled values.

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, FieldError, Label, SearchField } from "@lenso/ui";import * as React from "react";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", flexDirection: "column", gap: 16 },  input: { width: 280 },});export function WithValidation() {  const [value, setValue] = React.useState("");  const isInvalid = value.length > 0 && value.length < 3;  return (    <div {...stylex.props(styles.root)}>      <SearchField invalid={isInvalid} name="search">        <Label>Search</Label>        <SearchField.Group>          <SearchField.SearchIcon />          <SearchField.Input            required            xstyle={styles.input}            placeholder="Search..."            value={value}            onValueChange={setValue}          />          <SearchField.ClearButton />        </SearchField.Group>        {isInvalid ? (          <FieldError match>Search query must be at least 3 characters</FieldError>        ) : (          <Description style={{ display: "block" }}>            Enter at least 3 characters to search          </Description>        )}      </SearchField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Custom Icons

Customize the search icon and clear button icons.

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Label, SearchField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", flexDirection: "column", gap: 16 },  input: { width: 280 },});export function CustomIcons() {  return (    <div {...stylex.props(styles.root)}>      <SearchField name="search-custom">        <Label>Search (Custom Icons)</Label>        <SearchField.Group>          <SearchField.SearchIcon            height="16"            viewBox="0 0 16 16"            width="16"            xmlns="http://www.w3.org/2000/svg"            fill="none"            stroke="none"          >            <path              clipRule="evenodd"              d="M12.5 4c0 .174-.071.513-.885.888S9.538 5.5 8 5.5s-2.799-.237-3.615-.612C3.57 4.513 3.5 4.174 3.5 4s.071-.513.885-.888S6.462 2.5 8 2.5s2.799.237 3.615.612c.814.375.885.714.885.888m-1.448 2.66C10.158 6.888 9.115 7 8 7s-2.158-.113-3.052-.34l1.98 2.905c.21.308.322.672.322 1.044v3.37q.088.02.25.021c.422 0 .749-.14.95-.316c.185-.162.3-.38.3-.684v-2.39c0-.373.112-.737.322-1.045zM8 1c3.314 0 6 1 6 3a3.24 3.24 0 0 1-.563 1.826l-3.125 4.584a.35.35 0 0 0-.062.2V13c0 1.5-1.25 2.5-2.75 2.5s-1.75-1-1.75-1v-3.89a.35.35 0 0 0-.061-.2L2.563 5.826A3.24 3.24 0 0 1 2 4c0-2 2.686-3 6-3m-.88 12.936q-.015-.008-.013-.01z"              fill="currentColor"              fillRule="evenodd"            />          </SearchField.SearchIcon>          <SearchField.Input xstyle={styles.input} placeholder="Search..." />          <SearchField.ClearButton>            <svg              aria-hidden="true"              height="16"              viewBox="0 0 16 16"              width="16"              xmlns="http://www.w3.org/2000/svg"            >              <path                clipRule="evenodd"                d="M8 15A7 7 0 1 0 8 1a7 7 0 0 0 0 14M6.53 5.47a.75.75 0 0 0-1.06 1.06L6.94 8L5.47 9.47a.75.75 0 1 0 1.06 1.06L8 9.06l1.47 1.47a.75.75 0 1 0 1.06-1.06L9.06 8l1.47-1.47a.75.75 0 1 0-1.06-1.06L8 6.94z"                fill="currentColor"                fillRule="evenodd"              />            </svg>          </SearchField.ClearButton>        </SearchField.Group>        <Description>Custom icon children</Description>      </SearchField>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

With Keyboard Shortcut

Add keyboard shortcuts to quickly focus the search field.

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Description, Kbd, Label, SearchField } from "@lenso/ui";import * as React from "react";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { display: "flex", flexDirection: "column", gap: 16 },  input: { width: 280 },  hint: {    display: "flex",    alignItems: "center",    gap: 8,    fontSize: 14,    color: "var(--default-500)",  },});export function WithKeyboardShortcut() {  const inputRef = React.useRef<HTMLInputElement>(null);  const [value, setValue] = React.useState("");  React.useEffect(() => {    const handleKeyDown = (event: KeyboardEvent) => {      if (        event.shiftKey &&        event.key === "S" &&        !event.metaKey &&        !event.ctrlKey &&        !event.altKey      ) {        event.preventDefault();        inputRef.current?.focus();      }      if (event.key === "Escape" && document.activeElement === inputRef.current)        inputRef.current?.blur();    };    window.addEventListener("keydown", handleKeyDown);    return () => window.removeEventListener("keydown", handleKeyDown);  }, []);  return (    <div {...stylex.props(styles.root)}>      <div>        <SearchField name="search">          <Label>Search</Label>          <SearchField.Group>            <SearchField.SearchIcon />            <SearchField.Input              ref={inputRef}              xstyle={styles.input}              placeholder="Search..."              value={value}              onValueChange={setValue}            />            <SearchField.ClearButton />          </SearchField.Group>          <Description>Use keyboard shortcut to quickly focus this field</Description>        </SearchField>      </div>      <div {...stylex.props(styles.hint)}>        <span>Press</span>        <Kbd>          <Kbd.Abbr keyValue="shift" />          <Kbd.Content>S</Kbd.Content>        </Kbd>        <span>to focus the search field</span>      </div>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Render Function

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, SearchField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({ input: { width: 280 } });export function RenderFunction() {  return (    <SearchField name="search" render={(props) => <div {...props} data-custom="foo" />}>      <Label>Search</Label>      <SearchField.Group>        <SearchField.SearchIcon />        <SearchField.Input xstyle={styles.input} placeholder="Search..." />        <SearchField.ClearButton />      </SearchField.Group>    </SearchField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Customization

Tailwind CSS

"use client";// Adapted from HeroUI v3.2.6 (e385ac202b2cdb94b1bf6fa76d32c31c8259cc5e), Apache-2.0.import { Label, SearchField } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";const styles = stylex.create({  root: { width: "100%", maxWidth: 256 },  label: { fontWeight: 500, color: "var(--foreground)" },  group: { borderRadius: 12, backgroundColor: "var(--default)" },  muted: { color: "var(--muted)" },  input: { "::placeholder": { color: "var(--muted)" } },});export function CustomStyles() {  return (    <SearchField xstyle={styles.root} name="docs" variant="secondary">      <Label xstyle={styles.label}>Search docs</Label>      <SearchField.Group xstyle={styles.group}>        <SearchField.SearchIcon xstyle={styles.muted} />        <SearchField.Input xstyle={styles.input} placeholder="Components, guides..." />        <SearchField.ClearButton xstyle={styles.muted} />      </SearchField.Group>    </SearchField>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

Global CSS

SearchField uses CSS classes that can be customized. Override the component classes to match your design system.

@layer components {  .search-field {    @apply flex flex-col gap-1;  }
  /* When invalid, the description is hidden automatically */  .search-field[data-invalid],  .search-field[aria-invalid] {    [data-slot="description"] {      @apply hidden;    }  }
  .search-field__group {    @apply bg-field text-field-foreground shadow-field rounded-field inline-flex h-9 items-center overflow-hidden border;  }
  .search-field__input {    @apply flex-1 rounded-none border-0 bg-transparent px-3 py-2 shadow-none outline-none;  }
  .search-field__search-icon {    @apply text-field-placeholder pointer-events-none shrink-0 ml-3 mr-0 size-4;  }
  .search-field__clear-button {    @apply mr-1 shrink-0;  }}

Styling Reference

HeroUI follows the BEM methodology to ensure component variants and states are reusable and easy to customize.

CSS Classes

Base Classes [!toc]

  • .search-field – Root container with minimal styling (flex flex-col gap-1)
  • .search-field__group – Container for search icon, input, and clear button with border and background styling
  • .search-field__input – The search input field
  • .search-field__search-icon – The search icon displayed on the left
  • .search-field__clear-button – Button to clear the search field

Variant Classes [!toc]

  • .search-field--primary – Primary variant with shadow (default)
  • .search-field--secondary – Secondary variant without shadow, suitable for use in surfaces

Note: Child components (Label, Description, FieldError) have their own CSS classes and styling. See their respective documentation for customization options.

Interactive States

SearchField automatically manages these data attributes based on its state:

  • Invalid: [data-invalid="true"] or [aria-invalid="true"] - Automatically hides the description slot when invalid
  • Disabled: [data-disabled="true"] - Applied when isDisabled is true
  • Focus Within: [data-focus-within="true"] - Applied when the input is focused
  • Focus Visible: [data-focus-visible="true"] - Applied when focus is visible (keyboard navigation)
  • Hovered: [data-hovered="true"] - Applied when hovering over the group
  • Empty: [data-empty="true"] - Applied when the field is empty (hides clear button)

Additional attributes are available through render props (see SearchFieldRenderProps below).

API Reference

SearchField

SearchField inherits all props from React Aria's SearchField component.

Base Props

PropTypeDefaultDescription
childrenReact.ReactNode | (values: SearchFieldRenderProps) => React.ReactNode-Child components (Label, Group, Input, etc.) or render function.
classNamestring | (values: SearchFieldRenderProps) => string-CSS classes for styling, supports render props.
styleReact.CSSProperties | (values: SearchFieldRenderProps) => React.CSSProperties-Inline styles, supports render props.
fullWidthbooleanfalseWhether the search field should take full width of its container
idstring-The element's unique identifier.
variant"primary" | "secondary""primary"Visual variant of the component. primary is the default style with shadow. secondary is a lower emphasis variant without shadow, suitable for use in surfaces.
renderDOMRenderFunction<keyof React.JSX.IntrinsicElements, SearchFieldRenderProps>-Overrides the default DOM element with a custom render function.

Value Props

PropTypeDefaultDescription
valuestring-Current value (controlled).
defaultValuestring-Default value (uncontrolled).
onChange(value: string) => void-Handler called when the value changes.

Validation Props

PropTypeDefaultDescription
isRequiredbooleanfalseWhether user input is required before form submission.
isInvalidboolean-Whether the value is invalid.
validate(value: string) => ValidationError | true | null | undefined-Custom validation function.
validationBehavior'native' | 'aria''native'Whether to use native HTML form validation or ARIA attributes.
validationErrorsstring[]-Server-side validation errors.

State Props

PropTypeDefaultDescription
isDisabledboolean-Whether the input is disabled.
isReadOnlyboolean-Whether the input can be selected but not changed.

Form Props

PropTypeDefaultDescription
namestring-Name of the input element, for HTML form submission.
autoFocusboolean-Whether the element should receive focus on render.

Event Props

PropTypeDefaultDescription
onSubmit(value: string) => void-Handler called when the user submits the search (Enter key).
onClear() => void-Handler called when the clear button is pressed.

Accessibility Props

PropTypeDefaultDescription
aria-labelstring-Accessibility label when no visible label is present.
aria-labelledbystring-ID of elements that label this field.
aria-describedbystring-ID of elements that describe this field.
aria-detailsstring-ID of elements with additional details.

Composition Components

SearchField works with these separate components that should be imported and used directly:

  • SearchField.Group - Container for search icon, input, and clear button
  • SearchField.Input - The search input field
  • SearchField.SearchIcon - The search icon displayed on the left
  • SearchField.ClearButton - Button to clear the search field
  • Label - Field label component from @lenso/ui
  • Description - Helper text component from @lenso/ui
  • FieldError - Validation error message from @lenso/ui

Each of these components has its own props API. Use them directly within SearchField for composition:

<SearchField isRequired isInvalid={hasError} value={value} onChange={setValue}>  <Label>Search</Label>  <SearchField.Group>    <SearchField.SearchIcon />    <SearchField.Input placeholder="Search..." />    <SearchField.ClearButton />  </SearchField.Group>  <Description>Enter keywords to search</Description>  <FieldError>Search query is required</FieldError></SearchField>

SearchField.Group Props

SearchField.Group inherits props from React Aria's Group component.

PropTypeDefaultDescription
childrenReact.ReactNode | (values: GroupRenderProps) => React.ReactNode-Child components (SearchIcon, Input, ClearButton) or render function.
classNamestring | (values: GroupRenderProps) => string-CSS classes for styling.

SearchField.Input Props

SearchField.Input inherits props from React Aria's Input component.

PropTypeDefaultDescription
classNamestring-CSS classes for styling.
variant"primary" | "secondary""primary"Visual variant of the input. primary is the default style with shadow. secondary is a lower emphasis variant without shadow, suitable for use in surfaces.
placeholderstring-Placeholder text displayed when the input is empty.
typestring"search"Input type (automatically set to "search").

SearchField.SearchIcon Props

SearchField.SearchIcon is a custom component that renders the search icon.

PropTypeDefaultDescription
childrenReact.ReactNode<IconSearch />Custom icon element. Defaults to search icon.
classNamestring-CSS classes for styling.

SearchField.ClearButton Props

SearchField.ClearButton inherits props from React Aria's Button component.

PropTypeDefaultDescription
childrenReact.ReactNode<CloseButton icon />Icon or content for the button. Defaults to close icon.
classNamestring-CSS classes for styling.
slot"clear""clear"Must be set to "clear" (automatically set).

Render Props

When using render props with className, style, or children, these values are available:

PropTypeDescription
isDisabledbooleanWhether the field is disabled.
isInvalidbooleanWhether the field is currently invalid.
isReadOnlybooleanWhether the field is read-only.
isRequiredbooleanWhether the field is required.
isFocusedbooleanWhether the field is currently focused (DEPRECATED - use isFocusWithin).
isFocusWithinbooleanWhether any child element is focused.
isFocusVisiblebooleanWhether focus is visible (keyboard navigation).
valuestringCurrent value.
isEmptybooleanWhether the field is empty.

See upstream SearchField showcases. Product showcases are not part of the local component runtime.