Toggle

v0.0.10

v0.0.10StableHeadlessStatelessAccessibleJSApache-2.0
Installation mix mishka.ui.gen.headless toggle
Source View Source

Overview of the Phoenix and LiveView Headless Toggle Component

The Mishka Chelekom Headless Toggle is a two-state pressed button for Phoenix LiveView with no styling of its own. The root is a native button wired to the shared Toggle hook: a click, or Enter or Space, flips the pressed state, and the hook keeps aria-pressed and data-pressed in step. data-pressed is present only while the toggle is on. disabled ignores interaction and sets data-disabled. Give the toggle a name and it renders a hidden checkbox that the hook keeps in sync, so it submits with a form the way the switch does.

The root takes class and the hidden checkbox takes input_class.

Base UI Toggle example (Phoenix headless)

Click the heart, or focus it and press Enter or Space, to fill it.

Base UI Toggle example (Phoenix headless)

heex
<.toggle
  id="baseui-toggle-hero"
  aria-label="Favorite"
  class="flex size-8 items-center justify-center border-none rounded-none bg-transparent text-neutral-950 dark:text-white select-none hover:not-data-[disabled]:bg-neutral-100 dark:hover:not-data-[disabled]:bg-neutral-800 active:not-data-[disabled]:bg-neutral-200 dark:active:not-data-[disabled]:bg-neutral-700 data-[pressed]:text-neutral-950 dark:data-[pressed]:text-white focus-visible:outline-2 focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white group"
>
  <.icon name="hero-heart-solid" class="hidden size-4 group-data-[pressed]:block" />
  <.icon name="hero-heart" class="block size-4 group-data-[pressed]:hidden" />
</.toggle>

Attributes and slots

The Toggle hook mounts only on an element that has an id, so pass one even though the attribute is optional. pressed sets the state on render and disabled ignores every press. value names the toggle in a group, and is the value submitted while it is on when the toggle has a name; it defaults to "on".

For a form, give the toggle a name. It then renders a hidden checkbox that submits value while the toggle is on. unchecked_value adds a second hidden input, so a value is submitted while it is off too, and form names the form the inputs belong to when the toggle is rendered outside it. input_class adds classes to the hidden checkbox. on_change is a LiveView event pushed with %{"pressed" => true} or %{"pressed" => false} on every press, to the LiveView or LiveComponent that renders the toggle.

The default slot is the label or icon inside the button.

Parts & data attributes

The root button carries the state. When the toggle has a name, a hidden checkbox sits inside it.

PartElementARIA / data attributesPurpose
Rootbuttonaria-pressed, data-pressed, data-disabled, data-valueThe toggle button itself; carries the pressed and disabled state; takes class.
Inputinput (checkbox)aria-hidden, tabindex="-1"Hidden checkbox that carries the value for form submission; rendered when the toggle has a name; takes input_class.

Accessibility

Follows the WAI-ARIA Button (Toggle) pattern: the root is a native button with aria-pressed reflecting the current state, and both Enter and Space toggle it. A toggle that holds only an icon needs an aria-label, as the example does.