Breadcrumb

v0.0.10

v0.0.10StableHeadlessStatelessAccessibleJS-moduleApache-2.0
Installation mix mishka.ui.gen.headless breadcrumb
Source View Source

Overview of the Phoenix and LiveView Headless Breadcrumb Component

The Mishka Chelekom Headless Breadcrumb is a function component for Phoenix and LiveView that draws the trail back up a page hierarchy. The root is a <nav> with an accessible name and the trail is an <ol>, because the order carries meaning. The last crumb renders as <span aria-current="page"> so it is not a link to the page you are already on, and the separators are aria-hidden, so a screen reader reads the trail as words.

The component ships no colors, spacing or sizes. The root takes class and each part takes its own attribute: list_class, item_class, separator_class, ellipsis_class and link_class. max_items shortens a long trail on the server, with no JavaScript.

Base UI Breadcrumb example - basic trail (Phoenix headless)

The last crumb is the current page, so it is drawn as text. The other two crumbs are links through href.

Base UI Breadcrumb example - basic trail (Phoenix headless)

heex
<.breadcrumb
  id="baseui-breadcrumb-hero"
  class="text-sm text-neutral-600 dark:text-neutral-400"
  list_class="flex items-center gap-1"
  item_class="flex items-center gap-1"
  separator_class="px-1 text-neutral-400 dark:text-neutral-600"
>
  <:item href="#">Home</:item>
  <:item href="#">Projects</:item>
  <:item>Chelekom</:item>
</.breadcrumb>

Base UI Breadcrumb example - collapsed long trail (Phoenix headless)

With max_items={3} a trail of five crumbs keeps the first and the last crumb, and an ellipsis stands in for the three between them. The root gets data-collapsed while the trail is shortened.

Base UI Breadcrumb example - collapsed long trail (Phoenix headless)

heex
<.breadcrumb
  id="baseui-breadcrumb-collapsed"
  max_items={3}
  class="text-sm text-neutral-600 dark:text-neutral-400"
  list_class="flex items-center gap-1"
  item_class="flex items-center gap-1"
  separator_class="px-1 text-neutral-400 dark:text-neutral-600"
>
  <:item href="#">Home</:item>
  <:item href="#">Projects</:item>
  <:item href="#">Chelekom</:item>
  <:item href="#">Headless</:item>
  <:item>Breadcrumb</:item>
</.breadcrumb>

Separator slot

Without a separator slot every gap between crumbs holds a / character and the separator carries data-default. The slot content replaces it, and it is rendered once for each gap.

heex
<.breadcrumb separator_class="px-1 text-neutral-400">
  <:separator><.icon name="hero-chevron-right" class="size-3" /></:separator>
  <:item navigate={~p"/"}>Home</:item>
  <:item navigate={~p"/docs"}>Docs</:item>
  <:item>Breadcrumb</:item>
</.breadcrumb>

Collapsing a long trail with max_items

max_items shortens the trail once it has more crumbs than that number. boundary (default 1) is how many crumbs stay at each end. A trail of boundary * 2 + 1 crumbs or fewer is left whole, because the ellipsis would hide one crumb at most. The default for max_items is nil, which never collapses.

By default the ellipsis is a plain <span> and takes no tab stop. Pass on_expand, a LiveView event name or a Phoenix.LiveView.JS command, and it becomes a <button type="button"> named by expand_label (default Show all). The component does not expand itself. Your handler renders the trail again without max_items.

heex
<.breadcrumb max_items={@max_items} on_expand="expand_trail" expand_label="Show all pages">
  <:item :for={crumb <- @trail} navigate={crumb.path}>{crumb.title}</:item>
</.breadcrumb>
elixir
def handle_event("expand_trail", _params, socket) do
  {:noreply, assign(socket, :max_items, nil)}
end

Parts & data attributes

Each part carries a stable data-part and a structural chelekom-breadcrumb__* class you can target, plus the state attributes below.

Partdata-partState / ARIAPurpose
Rootrootaria-label, data-collapsedThe nav landmark. data-collapsed is present while the middle of the trail is elided.
Listlist-The ordered list.
Itemitemdata-indexOne list item for each crumb or ellipsis.
Separatorseparatoraria-hidden, data-defaultSits between items. data-default is present when the built-in / is used.
Linklinkaria-currentAn a element for a link, or a span for the current page and for a crumb with no address.
Ellipsisellipsisaria-labelA button when on_expand is given, otherwise a span.

Accessibility

Follows the WAI-ARIA Breadcrumb pattern: the trail is a labelled nav landmark holding an ordered list, and the current page is marked with aria-current="page". Tab moves through the links and Enter follows one. Separators are hidden from assistive technology. The collapsed ellipsis is focusable only when on_expand turns it into a button.