Action morphPro
A floating button that morphs into a quick-action menu, then an inline form, then back with a check.
$ pnpm dlx shadcn@4.23.0 add @xzero-ui-pro/action-morph- Type: Component (special)
- Access: Xzero Pro
- Page: https://ui.xzero.co.uk/components/action-morph
- Markdown: https://ui.xzero.co.uk/components/action-morph/markdown
- Source file:
registry/components/action-morph/action-morph.tsx - Dependencies: motion, lucide-react
- Keywords: special, new, react floating action button, fab menu, quick actions, morphing fab, inline composer, speed dial, quick create button
When to use
- Quick capture of tasks, notes, or comments without leaving the page.
- Apps with a few frequent create actions that deserve a persistent button.
- Mobile layouts where a corner button should expand into a small form.
When not to use
- Use dialog or drawer for longer forms with several fields.
- Use dropdown-menu when actions run immediately and need no input.
- Use action-button for one async save on a button in place.
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-pro/action-morph
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 { CheckSquare, StickyNote } from "lucide-react";
import { ActionMorph } from "@/components/xzero/action-morph/action-morph";
export function QuickCreate() {
return (
<div style={{ position: "fixed", right: 24, bottom: 24 }}>
<ActionMorph
label="Create"
actions={[
{
id: "task",
label: "New task",
description: "Add to your list",
icon: <CheckSquare strokeWidth={1.75} />,
shortcut: "t",
composer: {
title: "New task",
placeholder: "What needs doing?",
choices: { label: "Due", options: ["Today", "Tomorrow", "Next week"] },
submitLabel: "Add",
successLabel: "Task added",
},
},
{
id: "note",
label: "New note",
icon: <StickyNote strokeWidth={1.75} />,
shortcut: "n",
composer: { title: "New note", placeholder: "Write a note", multiline: true, submitLabel: "Save", successLabel: "Note saved" },
},
]}
onSubmit={({ action, text, choice }) => save(action, text, choice)}
/>
</div>
);
}
API reference
ActionMorph
A floating action button that springs into a quick action menu, slides into an inline composer, and folds back with a check on success.
| Prop | Type | Default | Description |
|---|---|---|---|
actions (required) | ActionMorphAction[] | – | Actions: { id, label, description?, icon, shortcut?, composer }. composer is { title, placeholder, multiline?, choices?, submitLabel, successLabel, emptyHint? }. |
label | string | "Create" | Accessible name of the button and the title of the menu. |
onSubmit | (submission: ActionMorphSubmission) => void | Promise<unknown> | – | Receives { action, text, choice? }. Return a promise to hold the sending state; a rejection keeps the composer open with the draft and an error. |
corner | "end" | "start" | "end" | Which bottom corner the button sits in. The surface grows away from it. |
resetAfter | number | 1600 | Milliseconds the check stays before the button returns to its plus. |
className | string | – | Extra class on the root, for example to position it fixed. |
Keyboard interactions
| Keys | Action |
|---|---|
| Enter / Space | Opens the menu from the button and focuses the first action. |
| ArrowDown / ArrowUp | Moves between menu actions, wrapping at the ends; Home and End jump to the first or last. |
| Letter shortcut | Opens that action's composer while the menu is open. |
| Enter | Submits a one line composer. |
| Mod + Enter | Submits a multiline composer. |
| Arrow keys | Move between choices in the composer's radio group. |
| Escape | Goes back from a composer to the menu, or closes the menu and returns focus to the button. |
Accessibility
- The button has aria-haspopup="menu"; after success its label adds the success message.
- The menu is role="menu" labelled by its title, with role="menuitem" buttons and aria-keyshortcuts for letter shortcuts.
- Composer fields set aria-invalid and aria-describedby on an empty or failed submit; the form sets aria-busy while sending.
- A polite status region announces the success label, and focus moves into each new face and back to the button on close.
Motion
- One surface animates width, height, and corner radius on physical springs: growing carries a little bounce, folding settles without overshoot.
- Going deeper slides the new face in from the right and pushes the old one left; menu rows stagger in; a highlight glides between actions.
- Submitting folds the composer into the button, which tints to success while a check draws itself, then the plus rotates back in.
- Reduced motion jumps the size, swaps faces with fades, drops the press scale and shake, and slows the spinner.
Responsive behavior
- The menu is min(16rem, 100vw - 2rem) wide and the composer min(20rem, 100vw - 2rem), so both fit narrow phones.
- corner="start" grows the surface to the right for bottom-left placement.
- The button is 56px with touch-action: manipulation; hover styles apply only on hover-capable fine pointers.
Performance
- Each face reports its size through a ResizeObserver only while it is current; the shape animates from those sizes.
- Only the current face and the one leaving are mounted.
Notes for AI
- Use for the two or three things people create most often on a page, such as a task, note, or event.
- Return the real promise from onSubmit; on rejection the draft stays and a retry message shows.
- Drafts are kept per action while the component is mounted, so going back and forth does not lose text.
- The component does not position itself; wrap it in a fixed container at the matching corner.
- For a single async commit use action-button; for longer forms use dialog or drawer.
Related
- Action button: A compact button for frequent toolbar actions.
- Orbit menu: Hold a button and its actions orbit out, ready to pick with a drag.
- Dropdown menu: A focused list of actions anchored to a trigger.
- Dialog: A focused surface for decisions that need attention.
- Toast: Brief confirmation for a completed background action.
Also in docks and tabs
- Share sheet: A Share button that opens into a panel with copy link, access level, channels, and people to send to.
- Morph nav: A navigation bar that morphs into rich menus, search, and a compact state as one surface.
- Dock: A floating tool dock with a gliding label, a springy selection, and trays that grow out of it.
- Liquid tab bar: Tabs with a lens selection that slides between them, swaps labels cleanly, and fills in icons as it passes.
Guidance for AI tools
Action morph: A floating button that morphs into a quick-action menu, then an inline form, then back with a check. 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