Burger

v0.0.10

v0.0.10StableHeadlessStatelessAccessibleApache-2.0
Installation mix mishka.ui.gen.headless burger
Source View Source

Overview of the Phoenix and LiveView Headless Burger Component

The Mishka Chelekom Headless Burger is the three-bar button that opens and closes a navigation menu. It is a Phoenix function component for LiveView apps and ships no colors, sizes or animation. It renders a native button with aria-expanded taken from opened, aria-controls pointing at the menu it toggles, and an aria-label, because the button has no visible text.

When opened is true the button also carries data-opened, so the bars can turn into a cross with CSS alone. Each bar is a span with data-part="line". class styles the button and line_class styles every bar.

Base UI Burger example - closed and opened (Phoenix headless)

Base UI Burger example - closed and opened (Phoenix headless)

heex
<div class="flex items-center gap-6">
  <.burger
    id="baseui-burger-closed"
    label="Open navigation"
    class="relative inline-flex size-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-100 dark:text-white dark:hover:bg-neutral-800 [&_[data-part=line]]:absolute [&_[data-part=line]]:h-0.5 [&_[data-part=line]]:w-5 [&_[data-part=line]]:rounded-full [&_[data-part=line]]:bg-current [&_[data-part=line]]:transition-all [&_[data-part=line]]:duration-200 [&_[data-part=line]:nth-child(1)]:-translate-y-1.5 [&_[data-part=line]:nth-child(3)]:translate-y-1.5 [&[data-opened]_[data-part=line]:nth-child(1)]:translate-y-0 [&[data-opened]_[data-part=line]:nth-child(1)]:rotate-45 [&[data-opened]_[data-part=line]:nth-child(2)]:opacity-0 [&[data-opened]_[data-part=line]:nth-child(3)]:translate-y-0 [&[data-opened]_[data-part=line]:nth-child(3)]:-rotate-45"
  />
  <.burger
    id="baseui-burger-opened"
    opened
    label="Close navigation"
    class="relative inline-flex size-9 items-center justify-center rounded-md text-neutral-900 hover:bg-neutral-100 dark:text-white dark:hover:bg-neutral-800 [&_[data-part=line]]:absolute [&_[data-part=line]]:h-0.5 [&_[data-part=line]]:w-5 [&_[data-part=line]]:rounded-full [&_[data-part=line]]:bg-current [&_[data-part=line]]:transition-all [&_[data-part=line]]:duration-200 [&_[data-part=line]:nth-child(1)]:-translate-y-1.5 [&_[data-part=line]:nth-child(3)]:translate-y-1.5 [&[data-opened]_[data-part=line]:nth-child(1)]:translate-y-0 [&[data-opened]_[data-part=line]:nth-child(1)]:rotate-45 [&[data-opened]_[data-part=line]:nth-child(2)]:opacity-0 [&[data-opened]_[data-part=line]:nth-child(3)]:translate-y-0 [&[data-opened]_[data-part=line]:nth-child(3)]:-rotate-45"
  />
</div>

Driving the open state

The burger does not toggle itself. Keep the state in your LiveView, pass it as opened, and change it from a phx-click event. Any phx-* attribute you add goes to the button. Set controls to the id of the menu so aria-controls points at it.

heex
<.burger id="nav-burger" opened={@nav_open?} controls="main-nav" phx-click="toggle_nav" />

<nav id="main-nav" hidden={!@nav_open?}>
  ...
</nav>
elixir
def mount(_params, _session, socket) do
  {:ok, assign(socket, :nav_open?, false)}
end

def handle_event("toggle_nav", _params, socket) do
  {:noreply, update(socket, :nav_open?, &(!&1))}
end

Attributes and parts

opened defaults to false and sets both aria-expanded and data-opened. label becomes the aria-label and defaults to "Toggle navigation". controls is written to aria-controls. disabled sets the native attribute and data-disabled. id is optional.

The root is a button with type="button" and the class chelekom-burger. The bars carry chelekom-burger__line. Other global attributes, such as phx-click, are passed to the button.

Accessibility

The burger follows the WAI-ARIA Disclosure pattern: a button that shows or hides a region. Enter and Space activate it, as they do for any button, and aria-expanded tells assistive technology whether the menu is open. Give the button a label that names the menu, because the bars carry no text.