Xzero UI
Pro library

Morph select

A select whose trigger grows into the list, with a gliding highlight and type-ahead.

$ pnpm dlx shadcn@4.23.0 add @xzero-ui/morph-select
Live · keyboard ready

When to use

When not to use

Installation

Register both Xzero UI namespaces in your project's components.json:

{
  "registries": {
    "@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
    "@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
  }
}
npx shadcn@4.23.0 add @xzero-ui/morph-select

Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.

Usage

import { useState } from "react";
import { MorphSelect } from "@/components/xzero/morph-select/morph-select";

export function TimezoneField() {
  const [zone, setZone] = useState<string | null>("europe/zurich");
  return (
    <MorphSelect
      label="Time zone"
      name="timezone"
      value={zone}
      onValueChange={setZone}
      items={[
        { label: "Europe", options: [
          { value: "europe/london", label: "London", meta: "UTC+0" },
          { value: "europe/zurich", label: "Zurich", meta: "UTC+1", keywords: "switzerland" },
        ] },
        { label: "Americas", options: [
          { value: "america/new_york", label: "New York", meta: "UTC−5" },
          { value: "america/los_angeles", label: "Los Angeles", meta: "UTC−8" },
        ] },
      ]}
    />
  );
}

API reference

MorphSelect

A select whose trigger grows into the option list, with groups, type-ahead, optional search, and a label that flies back into the trigger.

PropTypeDefaultDescription
label (required)string–Visible label, also the accessible name of the trigger and the list.
hideLabelbooleanfalseKeeps the label for assistive technology only.
items (required)MorphSelectItem[]–Options { value, label, icon?, meta?, keywords?, disabled? } or groups { label, options }, in display order.
valuestring | null–Controlled selected value.
defaultValuestring | nullnullUncontrolled starting value.
onValueChange(value: string, option: MorphSelectOption) => void–Called with the new value and its option.
placeholderstring"Select"Trigger text with no selection.
searchableboolean | "auto""auto"Shows a search field in place of the trigger when open. auto turns it on above eight options.
searchPlaceholderstring–Search field placeholder. Defaults to the selected label, then "Search".
panelWidthnumber272Width of the open surface in px. Never narrower than the trigger.
maxListHeightnumber296Tallest the option list gets before it scrolls, in px.
align"start" | "end""start"Which edge of the trigger stays put while the surface grows.
namestring–Adds a hidden input for native form submission.
disabledbooleanfalseDisables the trigger.
classNamestring–Extra class on the root.

Keyboard interactions

KeysAction
Enter / Space / ArrowDown / ArrowUpOpens the list on the selected option; Enter or Space picks the active option when open.
ArrowDown / ArrowUpMoves the active option, skipping disabled ones.
PageDown / PageUpMoves eight options at a time.
Home / EndMoves to the first or last option; when closed, opens on it.
Alt + ArrowUpPicks the active option and closes.
Printable charactersType-ahead jumps to a matching label, or starts a search when search is on.
EscapeCloses and returns focus to the trigger.
TabCloses and moves focus on without picking.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Also in selects

Guidance for AI tools

Morph select: A select whose trigger grows into the list, with a gliding highlight and type-ahead. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://ui.xzero.co.uk/llms.txt

Browse all components