Packages

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

Current section

Files

Jump to
glizzy src ui tabs.gleam
Raw

src/ui/tabs.gleam

// MIT License
// Copyright (c) 2026 Koncreate
// See LICENSE for details
import gleam/string
import lustre/attribute.{type Attribute, attribute, class, role}
import lustre/element.{type Element}
import lustre/element/html
import ui/css
import ui/size as size_helpers
pub type Variant {
Default
Bordered
Pill
}
pub type Size {
Small
Medium
Large
}
pub type Orientation {
Horizontal
Vertical
}
pub type KeyboardActivation {
Automatic
Manual
}
pub fn tabs(
attributes: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a) {
html.div([class("flex flex-col gap-2"), ..attributes], children)
}
pub fn tab_list(
attributes: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a) {
html.div(
[
class(
[
"flex border-b border-border gap-1",
]
|> string.join(" "),
),
role("tablist"),
attribute("aria-orientation", "horizontal"),
..attributes
],
children,
)
}
pub fn tab(
attributes: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a) {
html.button(
[
class(
[
"inline-flex items-center justify-center whitespace-nowrap px-4 py-2",
"text-sm font-medium transition-colors",
css.focus_ring(),
"disabled:pointer-events-none " <> css.disabled(),
"border-b-2 border-transparent",
"hover:border-border hover:bg-muted hover:text-muted-foreground",
"focus:bg-muted focus:text-muted-foreground",
]
|> string.join(" "),
),
role("tab"),
attribute("aria-selected", "false"),
attribute("aria-disabled", "false"),
attribute("tabindex", "-1"),
..attributes
],
children,
)
}
pub fn tab_panel(
attributes: List(Attribute(a)),
children: List(Element(a)),
) -> Element(a) {
html.div(
[
class(
[
"mt-2 focus-visible:outline-none",
]
|> string.join(" "),
),
role("tabpanel"),
attribute("tabindex", "0"),
..attributes
],
children,
)
}
pub fn variant(v: Variant) -> Attribute(a) {
case v {
Default -> class("")
Bordered -> class("rounded-md border border-border p-1")
Pill -> class("rounded-lg bg-muted p-1")
}
}
pub fn size(s: Size) -> Attribute(a) {
case s {
Small -> class(size_helpers.text_class(size_helpers.Small) <> " px-3 py-1")
Medium ->
class(size_helpers.text_class(size_helpers.Medium) <> " px-4 py-2")
Large -> class(size_helpers.text_class(size_helpers.Large) <> " px-5 py-3")
}
}
pub fn orientation(o: Orientation) -> Attribute(a) {
case o {
Horizontal -> attribute("aria-orientation", "horizontal")
Vertical -> attribute("aria-orientation", "vertical")
}
}
pub fn keyboard_activation(k: KeyboardActivation) -> Attribute(a) {
case k {
Automatic -> attribute("data-keyboard-activation", "automatic")
Manual -> attribute("data-keyboard-activation", "manual")
}
}
pub fn tab_disabled(disabled: Bool) -> Attribute(a) {
case disabled {
True -> attribute("aria-disabled", "true")
False -> attribute("aria-disabled", "false")
}
}
pub fn tab_selected(selected: Bool) -> Attribute(a) {
case selected {
True -> attribute("aria-selected", "true")
False -> attribute("aria-selected", "false")
}
}