Morph Search

A search button that stretches into a search field, with results unfolding underneath as one shape, and shrinks back into the button when it closes.

  • Search
  • Command Menu
  • Motion

Uses motion, clsx, tailwind-merge

Open in ChatGPTOpen in Claude
Northwind

Pages

Pricing

Plans for every team.

Installation

Add the component on its own with the CLI, or copy the file in by hand.

The CLI writes components/ui/morph-search.tsx and installs motion, clsx and tailwind-merge. It needs the @keyframeui registry in components.json; add it once per project.

npx shadcn@latest add @keyframeui/morph-search

Examples

Finished sections built with Morph Search. Each one installs whole, with the component included.

Command Menu

An app's command menu. The trigger travels to the middle of the screen, with grouped commands and their shortcuts. Opens with ⌘K.

Acme /Projects

Marketing site

Updated today

Mobile app

Updated today

Docs

Updated today

Billing service

Updated today

Design system

Updated today

Status page

Updated today

Docs Search

A docs header with a fake search field that becomes the real one. Press / to open it from anywhere.

Glidev3

Docs / Getting started

Introduction

What Glide is, and isn't.

Press / to search.

Props

itemsRequired

TypeMorphSearchItem[]

What to search. Each item has an id and label, and optionally a description, group, icon, shortcut (keys shown on the right) and keywords.

onSelect

Type(item: MorphSearchItem) => void

Called when a result is picked with Enter or a click. The search closes after.

variant

Type"inline" | "palette"Default"inline"

inline grows from the trigger in place, for a nav bar. palette travels to the middle of the screen over a dimmed page, for a command menu.

suggestions

TypeMorphSearchItem[]

Shown before anything is typed. Defaults to items.

placeholder

TypestringDefault"Search…"

Placeholder for the field. Also its accessible name.

hotkey

Typestring

"k" opens and closes it with ⌘K (Ctrl+K elsewhere). "/" opens it with a bare slash.

width

TypenumberDefault360 (inline), 560 (palette)

Width of the open field, in pixels. Never wider than the screen.

align

Type"start" | "end"

Inline only: which edge of the trigger the field grows from. Defaults to the side with more room.

filter

Type(item: MorphSearchItem, query: string) => number

Scores an item against the query. 0 hides it; higher ranks first. The default matches every word and ranks labels that start with the query first.

onQueryChange

Type(query: string) => void

Called as the query changes. For server results, update items from here and pass a filter that returns 1.

emptyMessage

Type(query: string) => React.ReactNode

Shown when nothing matches.

footer

TypebooleanDefaulttrue for palette

Keyboard hints under the results.

children

TypeReact.ReactNode

Custom trigger content, such as a fake search field. Use MorphSearchIcon for its magnifier so it slides into the open field.

className

Typestring

Classes for the trigger button. Its look and corner radius carry into the morph.

surfaceClassName

Typestring

Classes for the open surface's background. Defaults to bg-background.