Packages

A shadcn/ui-inspired UI library for Gleam and Lustre

Current section

Files

Jump to
glizzy src ui breadcrumbs.gleam
Raw

src/ui/breadcrumbs.gleam

// MIT License
// Copyright (c) 2026 Koncreate
// See LICENSE for details
import gleam/list
import gleam/option.{type Option, None, Some}
import lustre/attribute.{type Attribute, attribute, class}
import lustre/element.{type Element, text}
import lustre/element/html.{a, li, ol, span}
import ui/keyboard.{
type Key, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, End, Enter, Home,
decode_key,
}
import ui/size as size_helpers
pub type Size {
Small
Medium
Large
}
/// Messages for breadcrumbs keyboard navigation
pub type Msg {
MoveNext
MovePrev
MoveFirst
MoveLast
Navigate(String)
}
pub fn breadcrumbs(
attributes: List(Attribute(a)),
separator: Element(a),
children: List(Element(a)),
) -> Element(a) {
ol(
[
class("flex items-center gap-1.5"),
attribute("role", "navigation"),
attribute("aria-label", "Breadcrumb"),
..attributes
],
list.intersperse(children, separator),
)
}
pub fn item(attributes: List(Attribute(a))) -> Element(a) {
li([class("flex items-center gap-1.5"), ..attributes], [])
}
pub fn link(
attributes: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a) {
a(
[
class("transition-colors hover:text-foreground text-muted-foreground"),
..attributes
],
children,
)
}
pub fn separator() -> Element(a) {
span([class("text-muted-foreground")], [text("/")])
}
pub fn size(s: Size) -> Attribute(a) {
case s {
Small -> class(size_helpers.text_class(size_helpers.Small))
Medium -> class(size_helpers.text_class(size_helpers.Medium))
Large -> class(size_helpers.text_class(size_helpers.Large))
}
}
pub fn current() -> Attribute(a) {
attribute("aria-current", "page")
}
// ============================================================================
// Keyboard Navigation
// ============================================================================
/// Keymap for breadcrumbs keyboard navigation
///
/// ## Keyboard interactions:
/// - **Arrow keys**: Navigate between breadcrumb items
/// - **Enter**: Navigate to breadcrumb link
/// - **Home**: First breadcrumb
/// - **End**: Last breadcrumb
///
/// Follows WAI-ARIA [Breadcrumb](https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/) pattern.
pub fn keymap(key_event: keyboard.KeyEvent) -> Option(Msg) {
let key = decode_key(key_event.key)
case key {
ArrowRight | ArrowDown -> Some(MoveNext)
ArrowLeft | ArrowUp -> Some(MovePrev)
Home -> Some(MoveFirst)
End -> Some(MoveLast)
Enter -> Some(Navigate("current"))
_ -> None
}
}