MD3
Expressive
MATERIAL DESIGN 3 EXPRESSIVE

Search

A flexible, fully accessible search component with support for Docked and Full-screen views, profile avatar, and elevation tokens.

The Search component allows users to input search queries and view suggestions or results. Following the Material Design 3 Expressive guidelines, this component supports flexible display modes—collapsing into a pill-shaped SearchBar with Level 3 elevation shadow and expanding into a SearchView overlay with smooth Framer Motion layout transitions.

Introduction

The MD3 Expressive Search system is a highly modular set of components designed for both simple queries and complex filtering. It seamlessly transitions between a compact, non-intrusive pill (SearchBar) and a focused results view (SearchView). Using Framer Motion's shared element transitions, the expansion feels fluid and natural, anchoring the user's focus.

Anatomy

  • Search Bar (Collapsed): A pill-shaped input field (height 56dp, CornerFull) with Level 3 elevation shadow (elevation-3) and interactive hover/press state layers.
  • Search View (Active): The expanded panel (CornerExtraLarge 28dp radius in Docked, CornerNone in Full-screen) that displays suggestions and results.
  • Leading Icon: Typically a "Search" icon when collapsed, and a "Back" arrow or custom icon when active.
  • Input Field: The area for typing the query with animated placeholder support.
  • Trailing Actions: Icons for triggering secondary actions (e.g., Microphone, Camera) and a smooth animated "Clear" button (close) when text is typed.
  • Profile Avatar: A 30dp circular slot (SearchBarTokens.AvatarSize = 30dp) positioned at the trailing edge for user profile imagery or initials.
  • Results / Suggestions List: The scrollable area below the input with keyboard arrow navigation.

Variants

Docked View

The search view expands directly below the input field, keeping the rest of the screen visible. Ideal for desktop and tablet layouts.

  • Contained: The input and results share a single continuous container.
  • Divided: A horizontal line separates the input from the results.
  • Gap: An optional 2dp separation gap between the header and results panel (hasGap={true}).
Loading demo...

Full-screen View

The search view expands to cover the entire viewport using a React Portal. Best for mobile devices to provide maximum focus on results.

Loading demo...

Features

Profile Avatar & Flexible Trailing Actions

The component supports a dedicated avatar prop alongside trailingIcon. When the query is empty, both trailing action icons and user avatars are rendered with standard spacing. When the user types, the trailing action smoothly animates into a "Clear" button while maintaining the avatar slot.

Loading demo...

Shared Element Transitions

When the user focuses the SearchBar, it morphs into the SearchView header using a layoutId transition, ensuring a consistent visual anchor between states.

Interactive State Layer & Level 3 Elevation

The SearchBar container features MD3 Level 3 box-shadow elevation (SEARCH_ELEVATION.level3 / elevation-3) and a built-in StateLayer that provides visual feedback for hover (8% opacity) and pressed (12% opacity) interactions.

Text Alignment & Animated Placeholder

The placeholder text can be aligned ("left", "center", or "right") in the collapsed state and smoothly slides to the left as the field is focused via GPU-accelerated translateX transforms.

Usage

Basic Usage

import { useState } from "react";
import { Search } from "@bug-on/m3-expressive";

export function SearchExample() {
  const [query, setQuery] = useState("");
  const [active, setActive] = useState(false);

  return (
    <Search
      query={query}
      onQueryChange={setQuery}
      onSearch={(q) => console.log("Search:", q)}
      active={active}
      onActiveChange={setActive}
      placeholder="Search photos..."
    >
      <div className="p-4">
        {/* Render search results or suggestions with role="option" */}
        <p>Suggestions go here...</p>
      </div>
    </Search>
  );
}

With Avatar and Custom Trailing Action

import { Icon, Search } from "@bug-on/m3-expressive";

<Search
  query={query}
  onQueryChange={setQuery}
  active={active}
  onActiveChange={setActive}
  placeholder="Search with avatar..."
  trailingIcon={<Icon name="mic" className="size-5" />}
  avatar={
    <img
      src="/avatar.jpg"
      alt="User Profile"
      className="size-full object-cover"
    />
  }
>
  <SearchResults />
</Search>

Context Hook: Search.useSearch

Child result items inside the search view can consume the search context for keyboard navigation:

function SearchResultItem({ label, index, onSelect }: ResultItemProps) {
  const { activeIndex, listboxId } = Search.useSearch();
  const isHighlighted = activeIndex === index;

  return (
    <div
      id={`${listboxId}-option-${index}`}
      role="option"
      aria-selected={isHighlighted}
      tabIndex={-1}
      className={isHighlighted ? "bg-m3-surface-container-highest" : ""}
      onClick={onSelect}
    >
      {label}
    </div>
  );
}

Best Practices

Do

  • Use Docked search for desktop layouts and Full-screen for mobile screens.
  • Provide immediate visual feedback as the user types (live suggestions).
  • Utilize avatar for personalized user profile search bars (e.g., Google Account search).
  • Use Search.useSearch() to bind role="option" items to the active index for accessible keyboard navigation.

Don't

  • Don't hide the search entry point in deeply nested menus if search is a primary app function.
  • Avoid long delays in displaying search results; display loading states when fetching async suggestions.
  • Don't hardcode fixed widths on the SearchBar; allow responsive fluid layouts with className.

Accessibility

  • Roles: Correctly implements role="search" landmark and role="combobox" input.
  • States: Uses aria-expanded, aria-controls, and aria-activedescendant to communicate dropdown state to screen readers.
  • Keyboard Navigation: Navigate suggestions with ArrowDown / ArrowUp, select with Enter / Space, and close with Escape.
  • Focus Management: Automatically manages input focus during animated state transitions.

API Reference

PropTypeDefaultDescription
querystringRequired. Controlled search text value.
onQueryChange(query: string) => voidRequired. Callback invoked when input text changes.
onSearch(query: string) => voidRequired. Callback invoked when user submits search (Enter key or selection).
activebooleanfalseRequired. Controlled open/expanded state.
onActiveChange(active: boolean) => voidRequired. Callback invoked when search view should open or close.
variant"docked" | "fullscreen""docked"Expanded layout variant.
styleType"contained" | "divided""contained"Visual style for SearchView container (contained or divided).
placeholderstring"Search"Placeholder text when query is empty.
textAlign"left" | "center" | "right""left"Alignment of placeholder text in idle state.
hasGapbooleanfalse(Docked only) Adds a 2dp gap between header and results.
leadingIconReactNode<SearchIcon />Leading icon slot. Falls back to default search icon.
trailingIconReactNodeTrailing icon slot (e.g. mic, camera). Automatically switches to clear button when query is present.
avatarReactNodeProfile avatar slot (30dp circle). Rendered at the trailing edge.
classNamestringAdditional CSS class for the SearchBar root element.
viewClassNamestringAdditional CSS class for the SearchView container.
idstringuseId()Unique ID for the search input and Framer Motion layoutId.
aria-labelstring"Search"Accessible label for the search landmark.
childrenReactNodeSearch suggestions or results rendered inside the expanded view.

Tokens & Exports

ExportTypeDescription
SearchReact.ComponentMain orchestrator component with Search.useSearch context hook.
SearchBarReact.ComponentStandalone collapsed pill SearchBar.
SearchViewDockedReact.ComponentStandalone expanded docked popup view.
SearchViewFullScreenReact.ComponentStandalone expanded full-screen overlay view.
SearchTokensobjectDimensional tokens (heights, avatarSize: 30, iconSize: 20, dropdownGap: 2).
SEARCH_ELEVATIONobjectElevation utility class tokens (level3: "elevation-3").
SEARCH_COLORSobjectMD3 CSS custom property color references (container, leadingIcon, trailingIcon, inputText, divider, stateLayer).
useSearchKeyboardhookWAI-ARIA combobox keyboard navigation hook.