FAB
v0.0.10
mix mishka.ui.gen.headless fab
Overview of the Phoenix and LiveView Headless Fab Component
The Mishka Chelekom Headless Fab is an unstyled Phoenix function component for a floating action button that can fan out into a speed dial. The trigger is a real button driven by the shared Popup engine, so it carries aria-expanded, closes on Escape and on an outside click, and marks its popup with data-open or data-closed for your styles. With no actions it is just a button, and no popup is rendered.
The icon slot is the trigger's glyph and each action slot adds one item to the dial. In a LiveView page an action can push an event with on_click or navigate with navigate. The parts take trigger_class, icon_class, popup_class, action_class, action_icon_class, label_class and main_action_class, and the root takes class.
Base UI Fab example - speed dial with three actions (Phoenix headless)
Base UI Fab example - speed dial with three actions (Phoenix headless)
<div class="relative h-60 w-64 overflow-hidden rounded-lg border border-neutral-200 bg-white dark:border-neutral-800 dark:bg-neutral-950">
<.fab
id="baseui-fab-hero"
label="Actions"
contained
class="absolute right-3 bottom-3 flex flex-col-reverse items-end gap-2"
trigger_class="size-12 rounded-full border border-neutral-950 bg-neutral-950 text-lg text-white dark:border-white dark:bg-white dark:text-neutral-950 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white"
popup_class="flex flex-col-reverse items-end gap-2 data-closed:hidden"
action_class="inline-flex size-10 items-center justify-center rounded-full border border-neutral-200 bg-white text-sm text-neutral-950 hover:bg-neutral-100 dark:border-neutral-800 dark:bg-neutral-950 dark:text-white dark:hover:bg-neutral-800"
>
<:icon>+</:icon>
<:action label="Share">S</:action>
<:action label="Copy">C</:action>
<:action label="Edit">E</:action>
</.fab>
</div>Actions
Each action slot is one item of the dial, and its content is the glyph. label is required and becomes the item's aria-label. show_label also draws the label as text beside the glyph, in a span with data-part="label" that is hidden from assistive technology because the aria-label already says it. tip sets data-tip for a tooltip style. disabled sets data-disabled and, on a button, disables it. class adds classes to that one item.
An action is a button unless it has navigate, a LiveView navigation drawn as a link, or href, a plain link. In both cases it renders as an a. On a button, on_click takes a LiveView event name or a Phoenix.LiveView.JS command. Every item has role="menuitem" and a data-index.
<.fab id="compose-fab" label="Compose">
<:icon>+</:icon>
<:action label="Share" on_click="share">S</:action>
<:action label="Open drafts" navigate={~p"/drafts"} show_label>D</:action>
</.fab>Placement, direction and containment
placement is bottom-end by default, or bottom-start, top-end or top-start. direction is up by default, or down, left, right or flower. contained is a boolean. They are written to the root as data-placement, data-direction and data-contained, and your classes read them, for example data-[placement=bottom-end]:right-4 or data-contained:absolute. direction also sets data-side on the root, which the Popup engine uses to place the popup. flower is left entirely to your layout.
Close icon and main action
Fill close_icon to show another glyph while the dial is open. Both glyphs are rendered in spans marked data-part="icon", with data-state="closed" or data-state="open", and your CSS shows one of them using the popup's data-open. When close_icon is given, the trigger's aria-label is close_label, which defaults to Close, instead of label.
A main_action slot adds one more button to the popup, marked data-part="main-action". A style can lay it over the trigger while the dial is open. It takes label (required), on_click, navigate, href and class, and main_action_class is added on top of action_class.
Choosing an item closes the dial. When you build your own JS chain, the generated module has close/2. It removes data-open from the popup, sets data-closed, and sets aria-expanded to false on the trigger.
Parts & data attributes
The root carries data-part="root", data-side, data-align, data-placement, data-direction and data-contained. The parts are trigger, icon, popup, action, main-action and label. The popup has role="menu" and starts with data-closed. The Popup engine swaps that for data-open while the dial is open. Each element also has a structural class such as chelekom-fab__popup.
Accessibility
Follows the WAI-ARIA Menu Button pattern. When there are actions, the trigger has aria-haspopup, aria-expanded and aria-controls. Enter or Space opens the dial and moves focus to the first action. Tab moves through the actions. Escape closes the dial and returns focus to the trigger. A click outside it closes the dial too. The popup is named by label.
The items are reached with Tab. The arrow keys do not move between them.
Attributes
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
id
|
string
| — | — | Yes | Unique id (carries the Popup hook) |
label
|
string
| — | — | Yes | Accessible name for the trigger |
placement
|
string
|
bottom-end
|
bottom-endbottom-starttop-endtop-start
| No | Which corner the button floats in |
contained
|
boolean
|
false
| — | No | Drop the fixed positioning so the button floats inside its container |
direction
|
string
|
up
|
updownleftrightflower
| No | Where the actions fan out; `flower` is daisyUI's quarter-circle |
close_label
|
string
|
Close
| — | No | Accessible name for the trigger once it is open, when `close_icon` is given |
class
|
any
| — | — | No | Extra classes for the root |
trigger_class
|
any
| — | — | No | — |
popup_class
|
any
| — | — | No | — |
action_class
|
any
| — | — | No | — |
main_action_class
|
any
| — | — | No | — |
icon_class
|
any
| — | — | No | — |
action_icon_class
|
any
| — | — | No | — |
label_class
|
any
| — | — | No | — |
rest
|
global
| — | — | No | — |
Slots
| Name | Required | Description |
|---|---|---|
icon
| Yes | The trigger's glyph |
close_icon
| No | Replaces the trigger's glyph while open |
main_action
| No | Replaces the trigger entirely while open — daisyUI's `fab-main-action` |
action
| No | One action in the speed dial |
Attributes of the main_action slot
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
label
|
string
| — | — | Yes | — |
on_click
|
any
| — | — | No | — |
navigate
|
string
| — | — | No | — |
href
|
string
| — | — | No | — |
class
|
any
| — | — | No | — |
Attributes of the action slot
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
label
|
string
| — | — | Yes | The action's name |
show_label
|
boolean
| — | — | No | Render the label beside the glyph as well as announcing it |
on_click
|
any
| — | — | No | — |
navigate
|
string
| — | — | No | — |
href
|
string
| — | — | No | — |
disabled
|
boolean
| — | — | No | — |
tip
|
string
| — | — | No | Tooltip text (daisyUI reads `data-tip`) |
class
|
any
| — | — | No | — |
Options
Each option takes one or more of its values, separated by commas.
| Option | Values |
|---|---|
--type
|
fab
|
--module
| A module name of your own |
What it generates
mix mishka.ui.gen.headless fab