OTTODesign System

Code

Search Field

Storybook group: Components · Sidebar path: Components/Search Field · Extracted 28.09.2026

Version Tag Status API
v1 <oc-search-field-v1> Stable, allowed for generation SearchFieldV1

Overview (v1)

Source: ./src/components/search-field/v1/Overview.mdx

Search field

The search field component is a special component to provide search functionality to a feature. Please note that this component acts as a style-only-component and is only providing necessary styling and events. You need to implement the actual search functionality yourself.

Default variation

Story Default:

<oc-search-field-v1>
  <input
      type="search"
      placeholder="Wonach suchst du?"
      spellcheck="false"
    />
</oc-search-field-v1>

Configuration

The search field component is available in just one variant but can have 3 types of search-button styles without, primary and secondary. It also provides over-color which is intended to use, whenever the component is used on colored surfaces. This component is configurable, allowing you to tailor its features and appearance to your specific needs. To explore all the available options and adjust the component, use the component configurator and see the changes affect the component in real-time.

Usage guidelines

Before integrating the search field component into your project, make sure you have correctly installed the OTTO components package. Look through the variations page for examples of possible component variations. Here, you can discover both common and specific variations that address different use cases.

Info

See the Search field UX documentation for detailed user experience guidelines.

Layout considerations

This component has visual overflow. It extends beyond its bounding box and is clipped by parent containers with overflow: hidden. Ensure the parent container has sufficient padding to accommodate the component's full visual area.

Accessibility

The search field component comes with a set of built-in accessibility features to ensure a seamless experience for all users.

Events

The component comes with a set of events that can be used for your search functionality.

Name Purpose Returns
oc-search-field-input Whenever the search field component receives input or the input changes, this event fires. { searchTerm: string | undefined }
oc-search-field-clear Whenever the search field's input has been cleared manually via the clear-button, or ESC this event fires void
oc-search-field-search Whenever the search field component's search-button has been clicked or the Enter-Button has been pressed, while the search field is not empty, this event fires. { searchTerm: string | undefined }

Configuration (v1)

Source: ./src/components/search-field/v1/Configuration.mdx

Search field configuration

Configure the search field component with the controls below and see the changes live in the preview canvas. Click the Show code button within the preview canvas to see the source code for the current component configuration.

Story Default:

<oc-search-field-v1>
  <input
      type="search"
      placeholder="Wonach suchst du?"
      spellcheck="false"
    />
</oc-search-field-v1>

Interactive configurator (Storybook controls); every option is listed in the API section of this file.

API v1

Source: ./src/components/search-field/v1/SearchFieldV1.API.g.mdx

Search Field v1 API

API: <oc-search-field-v1> (SearchFieldV1)

The search field component is a special component to provide search functionality to a feature. Take note that this component acts as a style-only-component and only provides necessary styling and events. You need to implement the actual search functionality yourself.

Attributes / properties
Attribute Type Default Required Description
search-button-type "primary" | "secondary" | "none" "secondary" no Selects the style of the search button to be used.
over-color boolean false no Indicates whether the search field is displayed with an over-color style.

This style is intended to be used on colored backgrounds.
clear-button-aria-label string "Suchbegriff löschen" no Sets the aria-label for the clear button.
search-button-aria-label string "Suche abschicken" no Sets the aria-label for the search button.
Slots
Slot Required Description
default yes The input element for the search field.

Note: The only supported input type is search.
Events
Event Detail type Description
oc-search-field-input CustomEvent<{ searchTerm: string | undefined; }> Triggered when there is input in the search field.
oc-search-field-clear CustomEvent<void> Triggered when the clear button is pressed.
oc-search-field-search CustomEvent<{ searchTerm: string | undefined; }> Triggered when the search button is pressed.
oc-property-change OcSearchFieldV1Events["oc-property-change"] Whenever a property value changes, this event triggers. Use this event to track all property changes within the component.

Refer to the Events documentation for more information.
oc-mount { component: string; } Fired when the component is mounted to the DOM. The event is fired when the onMount hook of the component is called by the runtime.
oc-unmount { component: string; } Fired when the component is unmounted from the DOM. The event is fired when the function returned by the onMount hook of the component is called by the runtime.

Variations (v1)

Source: ./src/components/search-field/v1/Variations.mdx

Variations

Listed below are the most common variations of the search field component as well as specific component variations for different use cases.

You can explore all available options using the component configurator, adjust the component to your needs, and see the changes live in a preview canvas.

Default

Story: components-search-field-variations--default · tags: components, search-field, 1, variations

Default Component

<oc-search-field-v1>
  <input
      type="search"
      placeholder="Wonach suchst du?"
      spellcheck="false"
    />
</oc-search-field-v1>

Over-Color

Story: components-search-field-variations--over-color · tags: components, search-field, 1, variations

Over-Color Variation

Args: over-color=true, search-button-type=primary

<oc-search-field-v1 over-color search-button-type="primary">
  <input
      type="search"
      placeholder="Wonach suchst du?"
      spellcheck="false"
    />
</oc-search-field-v1>

Custom Aria Labels

Story: components-search-field-variations--custom-aria-label · tags: components, search-field, 1, variations

Custom Aria-Labels

Args: over-color=true, search-button-type=primary, clear-button-aria-label=Suchbegriff ins Nirvana schicken, search-button-aria-label=Suchbegriff übersenden

<oc-search-field-v1 over-color search-button-type="primary" clear-button-aria-label="Suchbegriff ins Nirvana schicken" search-button-aria-label="Suchbegriff übersenden">
  <input
      type="search"
      placeholder="Wonach suchst du?"
      spellcheck="false"
    />
</oc-search-field-v1>

Demo: Search Buttons

Story: components-search-field-variations--demo-search-buttons · tags: components, search-field, 1, variations

Multiple Search-Fields showcasing the Search Button Variation

<div style="display: flex; flex-direction: column; gap: 16px;">
  <div
    style="display: flex; flex-direction: column; gap: 8px; outline: 1px dashed gray; padding: 16px;"
  >
    <h3>Over-Color Variation</h3>
    <p>Primary search button</p>
    <oc-search-field-v1 search-button-type="primary" over-color
      ><input
    type="search"
    placeholder="Wonach suchst du?"
    spellcheck="false"
  />
</oc-search-field-v1
    >

    <p>Secondary search button</p>
    <oc-search-field-v1 search-button-type="secondary" over-color
      ><input
    type="search"
    placeholder="Wonach suchst du?"
    spellcheck="false"
  />
</oc-search-field-v1
    >

    <p>Without search button</p>
    <oc-search-field-v1 search-button-type="none" over-color
      ><input
    type="search"
    placeholder="Wonach suchst du?"
    spellcheck="false"
  />
</oc-search-field-v1
    >
  </div>

  <div
    style="display: flex; flex-direction: column; gap: 8px; outline: 1px dashed gray; padding: 16px; background-color: var(--oc-semantic-color-canvas-background);"
  >
    <h3>Default Variation</h3>
    <p>Primary search button</p>
    <oc-search-field-v1 search-button-type="primary"
      ><input
    type="search"
    placeholder="Wonach suchst du?"
    spellcheck="false"
  />
</oc-search-field-v1
    >

    <p>Secondary search button</p>
    <oc-search-field-v1 search-button-type="secondary"
      ><input
    type="search"
    placeholder="Wonach suchst du?"
    spellcheck="false"
  />
</oc-search-field-v1
    >

    <p>Without search button</p>
    <oc-search-field-v1 search-button-type="none"
      ><input
    type="search"
    placeholder="Wonach suchst du?"
    spellcheck="false"
  />
</oc-search-field-v1
    >
  </div>
</div>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Demo: Search Buttons",
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  render(args) {
    const {
      defaultSlot
    } = args;
    return html` <div style="display: flex; flex-direction: column; gap: 16px;">
      <div
        style="display: flex; flex-direction: column; gap: 8px; outline: 1px dashed gray; padding: 16px;"
      >
        <h3>Over-Color Variation</h3>
        <p>Primary search button</p>
        <oc-search-field-v1 search-button-type="primary" over-color
          >${unsafeHTML(defaultSlot)}</oc-search-field-v1
        >

        <p>Secondary search button</p>
        <oc-search-field-v1 search-button-type="secondary" over-color
          >${unsafeHTML(defaultSlot)}</oc-search-field-v1
        >

        <p>Without search button</p>
        <oc-search-field-v1 search-button-type="none" over-color
          >${unsafeHTML(defaultSlot)}</oc-search-field-v1
        >
      </div>

      <div
        style="display: flex; flex-direction: column; gap: 8px; outline: 1px dashed gray; padding: 16px; background-color: var(--oc-semantic-color-canvas-background);"
      >
        <h3>Default Variation</h3>
        <p>Primary search button</p>
        <oc-search-field-v1 search-button-type="primary"
          >${unsafeHTML(defaultSlot)}</oc-search-field-v1
        >

        <p>Secondary search button</p>
        <oc-search-field-v1 search-button-type="secondary"
          >${unsafeHTML(defaultSlot)}</oc-search-field-v1
        >

        <p>Without search button</p>
        <oc-search-field-v1 search-button-type="none"
          >${unsafeHTML(defaultSlot)}</oc-search-field-v1
        >
      </div>
    </div>`;
  }
}

Interaction tests (SearchFieldV1.interactions.stories.ts)

Interaction test stories (automated tests, not usage patterns).

Should Have Focus

Story: components-search-field-interaction-tests--should-have-focus · tags: components, search-field, 1, interactions, play-fn

Story source (TypeScript, verbatim from Storybook)
{
  args: {},
  play: async ({
    canvasElement
  }) => {
    const input: HTMLInputElement = canvasElement.querySelector("input[type='search']")!;
    await userEvent.tab();
    await expect(document.activeElement, "Active focused element").toBe(input);
  }
}

Should Have Value On Input

Story: components-search-field-interaction-tests--should-have-value-on-input · tags: components, search-field, 1, interactions, play-fn

Story source (TypeScript, verbatim from Storybook)
{
  args: {},
  play: async ({
    canvasElement
  }) => {
    const input: HTMLInputElement = canvasElement.querySelector("input[type='search']")!;
    await userEvent.type(input, "Hello World");
    await expect(input.value, "Current input value").toBe("Hello World");
  }
}

Should Clear Value On Clear Button Click And Focus

Story: components-search-field-interaction-tests--should-clear-value-on-clear-button-click-and-focus · tags: components, search-field, 1, interactions, play-fn

Story source (TypeScript, verbatim from Storybook)
{
  args: {},
  play: async ({
    canvasElement
  }) => {
    const [searchFieldElement] = Array.from(canvasElement.getElementsByTagName("oc-search-field-v1"));
    const input: HTMLInputElement = canvasElement.querySelector("input[type='search']")!;
    await userEvent.type(input, "Hello World");
    await expect(input.value, "Current input value").toBe("Hello World");
    const clearButton: HTMLOcIconButtonV3Element = searchFieldElement.shadowRoot!.querySelector(".search-field__icon-button-controls__clear")!;
    await userEvent.click(clearButton);
    await expect(input.value, "Current input value").toBe("");
    await expect(document.activeElement, "Active focused element").toBe(input);
    await expect(input.selectionStart).toBe(0);
  }
}