Skip to main content

SpeedDial

A floating action button (FAB) that reveals a stack of secondary actions when clicked. Child actions fan out with staggered scale + slide animation. Built as a stateful Mates component.

Quick start
import { SpeedDial } from "mates-ui";
import { EditIcon, MailIcon, DownloadIcon } from "mates-icons";





SpeedDial({
  label: "Create",
  actions: [
    { icon: EditIcon(),             label: "Edit",     onClick: () => {} },
    { icon: MailIcon({ size: 20 }), label: "Email",    onClick: () => {} },
    { icon: DownloadIcon(),         label: "Download", onClick: () => {} },
  ],
})
      

Basic

import { html, renderApp } from 'mates';
import { SpeedDial } from 'mates-ui';
import { DownloadIcon, EditIcon, MailIcon } from 'mates-icons';

const App = () => () => html`
${SpeedDial({
label: "Create",
actions: [
{ icon: EditIcon(), label: "Edit", onClick: () => {} },
{ icon: MailIcon({ size: 20 }), label: "Email", onClick: () => {} },
{ icon: DownloadIcon(), label: "Download", onClick: () => {} },
],
})}
`;

renderApp(App, document.getElementById('app'));

Positions

import { html, atom, renderApp } from 'mates';
import { SpeedDial, OutlinedButton, FilledButton } from 'mates-ui';
import { DeleteIcon, EditIcon, ShareIcon } from 'mates-icons';

const POSITIONS = ["bottom-right", "bottom-left", "bottom-center", "top-right", "top-left"];

const App = () => {
const pos = atom("bottom-right");
return () => html`
<x-col gap="var(--md-space-4)">
<x-row gap="var(--md-space-2)" wrap>
${POSITIONS.map((p) => pos() === p
? FilledButton(p, { size: "sm", onClick: () => pos.set(p) })
: OutlinedButton(p, { size: "sm", onClick: () => pos.set(p) })
)}
</x-row>
${SpeedDial({
label: "Position demo",
position: pos(),
actions: [
{ icon: EditIcon(), label: "Edit", onClick: () => {} },
{ icon: ShareIcon(), label: "Share", onClick: () => {} },
{ icon: DeleteIcon(), label: "Delete", onClick: () => {} },
],
})}
</x-col>
`;
};

renderApp(App, document.getElementById('app'));

Custom trigger icon

import { html, renderApp } from 'mates';
import { SpeedDial } from 'mates-ui';
import { BookmarkIcon, DeleteIcon, FavoriteIcon, PrintIcon, ShareIcon } from 'mates-icons';

const App = () => () => html`
${SpeedDial({
label: "Favourites",
icon: FavoriteIcon({ size: 24 }),
position: "bottom-left",
actions: [
{ icon: BookmarkIcon(), label: "Bookmark", onClick: () => {} },
{ icon: ShareIcon(), label: "Share", onClick: () => {} },
{ icon: PrintIcon(), label: "Print", onClick: () => {} },
{ icon: DeleteIcon(), label: "Remove", onClick: () => {} },
],
})}
`;

renderApp(App, document.getElementById('app'));

Disabled actions

import { html, renderApp } from 'mates';
import { SpeedDial } from 'mates-ui';
import { DownloadIcon, EditIcon, MailIcon } from 'mates-icons';

const App = () => () => html`
${SpeedDial({
label: "Actions",
position: "bottom-center",
actions: [
{ icon: EditIcon(), label: "Edit", onClick: () => {} },
{ icon: MailIcon(), label: "Email (disabled)", onClick: () => {}, disabled: true },
{ icon: DownloadIcon(), label: "Download", onClick: () => {} },
],
})}
`;

renderApp(App, document.getElementById('app'));

SpeedDial

import { SpeedDial } from "mates-ui";
Prop Type Default Description
actions* SpeedDialAction[] Array of secondary actions — each with icon, label, onClick, and optional disabled.
attr AttrMap HTML attributes on the root element.
classes string | string[] Extra root classes — joined and appended after built-in classes.
closeOnAction boolean true Automatically close the dial after an action is clicked.
data DataAttrMap Root `data-*` map (`testId` → `data-testid`). `testId` prop / `attr` win over `data`.
defaultOpen boolean false Whether the dial starts in the open state.
icon IconInput Icon for the trigger FAB when closed. Defaults to a + plus sign.
iconOpen IconInput Icon for the trigger FAB when open. Defaults to an × close icon.
id string Root `id` shorthand (`attr.id` wins). Form native-control `id` props are unchanged.
label string Accessible aria-label for the trigger button.
on OnEventMap DOM event handlers on the root element.
position "bottom-right" | "bottom-left" | "bottom-center" | "top-right" | "top-left" "bottom-right" Corner where the FAB is fixed.
style StyleMap Inline CSS on the root element.