Basic
The most basic usage.
Code
<%= render Hakumi::Segmented::Component.new(
options: ["Daily", "Weekly", "Monthly"]
) %>
Vertical Direction
Make it vertical.
Code
<%= render(Hakumi::Space::Component.new(direction: :horizontal, size: :large)) do |space| %>
<% space.with_item do %>
<%= render(Hakumi::Segmented::Component.new(
options: ["Daily", "Weekly", "Monthly"],
vertical: true
)) %>
<% end %>
<% space.with_item do %>
<%= render(Hakumi::Segmented::Component.new(
options: [
{ label: nil, value: "list", icon: :unordered_list, aria_label: "List view" },
{ label: nil, value: "board", icon: :appstore, aria_label: "Board view" },
{ label: nil, value: "timeline", icon: :history, aria_label: "Timeline view" }
],
vertical: true
)) %>
<% end %>
<% end %>
Block Segmented
Block property will make the Segmented fit to its parent width.
Code
<%= render Hakumi::Card::Component.new(style: "max-width: 420px;") do %>
<%= render Hakumi::Segmented::Component.new(
options: ["Daily", "Weekly", "Monthly"],
block: true
) %>
<% end %>
Round shape
Round shape of Segmented.
Code
<%= render(Hakumi::Segmented::Component.new(
options: [
{ label: nil, value: "grid", icon: :appstore, aria_label: "Grid view" },
{ label: nil, value: "list", icon: :unordered_list, aria_label: "List view" },
{ label: nil, value: "timeline", icon: :history, aria_label: "Timeline view" }
],
round: true
)) %>
Disabled
Disabled Segmented.
Code
<%= render Hakumi::Segmented::Component.new(
options: ["Daily", "Weekly", "Monthly"],
value: "Weekly",
disabled: true
) %>
Controlled mode
Controlled Segmented.
Selected: Daily
Code
<%= render(Hakumi::Space::Component.new(direction: :vertical, size: :middle)) do |space| %>
<% space.with_item do %>
<%= render(Hakumi::Segmented::Component.new(
options: ["Daily", "Weekly", "Monthly"],
value: "Daily",
id: "segmented-controlled"
)) %>
<% end %>
<% space.with_item do %>
<%= render(Hakumi::Space::Component.new(size: :small)) do |actions| %>
<% actions.with_item do %>
<%= render(Hakumi::Button::Component.new(id: "segmented-set-weekly")) { "Set Weekly" } %>
<% end %>
<% actions.with_item do %>
<%= render(Hakumi::Button::Component.new(id: "segmented-set-monthly")) { "Set Monthly" } %>
<% end %>
<% end %>
<% end %>
<% space.with_item do %>
<%= render(Hakumi::Typography::Text::Component.new(id: "segmented-controlled-value")) { "Selected: Daily" } %>
<% end %>
<% end %>
<script>
(() => {
const segmented = document.getElementById("segmented-controlled")
const weeklyButton = document.getElementById("segmented-set-weekly")
const monthlyButton = document.getElementById("segmented-set-monthly")
const valueLabel = document.getElementById("segmented-controlled-value")
if (!segmented || !weeklyButton || !monthlyButton || !valueLabel) return
const updateLabel = (value) => {
valueLabel.textContent = `Selected: ${value || "-"}`
}
let wired = false
const wire = () => {
if (wired) return true
const api = segmented.hakumiSegmented
if (!api) return false
segmented.addEventListener("hakumi--segmented:change", (event) => {
updateLabel(event.detail.value)
})
weeklyButton.addEventListener("click", () => {
api.setValue("Weekly")
})
monthlyButton.addEventListener("click", () => {
api.setValue("Monthly")
})
updateLabel(api.getValue())
wired = true
return true
}
if (wire()) return
const onReady = () => {
if (wire()) {
document.removeEventListener("turbo:load", onReady)
window.removeEventListener("load", onReady)
}
}
document.addEventListener("turbo:load", onReady)
window.addEventListener("load", onReady)
})()
</script>
Custom Render
Custom each Segmented Item.
Code
<% launch_label = capture do %>
<%= render(Hakumi::Flex::Component.new(align: :center, gap: 8)) do %>
<%= render(Hakumi::Icon::Component.new(name: :rocket)) %>
<%= render(Hakumi::Typography::Text::Component.new(strong: true)) { "Launch" } %>
<% end %>
<% end %>
<% review_label = capture do %>
<%= render(Hakumi::Flex::Component.new(align: :center, gap: 8)) do %>
<%= render(Hakumi::Icon::Component.new(name: :audit)) %>
<%= render(Hakumi::Typography::Text::Component.new(type: :secondary)) { "Review" } %>
<% end %>
<% end %>
<%= render(Hakumi::Segmented::Component.new(
options: [
{ label: launch_label, value: "launch" },
{ label: review_label, value: "review" }
]
)) %>
Dynamic
Load options dynamically.
Click load to fetch options.
Code
<%= render Hakumi::Space::Component.new(direction: :vertical, size: :middle) do |space| %>
<% space.with_item do %>
<%= render(Hakumi::Button::Component.new(type: :primary, id: "segmented-load-options")) { "Load Options" } %>
<% end %>
<% space.with_item do %>
<%= render Hakumi::Container::Component.new(
id: "segmented-dynamic-target",
width: :fluid,
padded: false,
centered: false
) do %>
<%= render(Hakumi::Typography::Text::Component.new(type: :secondary)) { "Click load to fetch options." } %>
<% end %>
<% end %>
<% end %>
<script>
(() => {
const button = document.getElementById("segmented-load-options")
if (!button) return
const options = [
{ label: "Daily", value: "daily" },
{ label: "Weekly", value: "weekly" },
{ label: "Monthly", value: "monthly" }
]
let wired = false
const wire = () => {
if (wired) return true
if (!window.HakumiComponents?.renderComponent) return false
button.addEventListener("click", async () => {
await window.HakumiComponents.renderComponent("segmented", {
params: {
options: JSON.stringify(options),
value: "weekly",
block: true,
round: true
},
target: "#segmented-dynamic-target",
mode: "replace"
})
})
wired = true
return true
}
if (wire()) return
const onReady = () => {
if (wire()) {
document.removeEventListener("turbo:load", onReady)
window.removeEventListener("load", onReady)
}
}
document.addEventListener("turbo:load", onReady)
window.addEventListener("load", onReady)
})()
</script>
Three sizes of Segmented
Large (40px), default (32px) and small (24px).
Code
<%= render Hakumi::Space::Component.new(size: :middle) do |space| %>
<% space.with_item do %>
<%= render Hakumi::Segmented::Component.new(
options: ["Small", "Option"],
size: :small
) %>
<% end %>
<% space.with_item do %>
<%= render Hakumi::Segmented::Component.new(
options: ["Default", "Option"]
) %>
<% end %>
<% space.with_item do %>
<%= render Hakumi::Segmented::Component.new(
options: ["Large", "Option"],
size: :large
) %>
<% end %>
<% end %>
With Icon
Set icon for Segmented Item.
Code
<%= render Hakumi::Segmented::Component.new(
options: [
{ label: "List", value: "list", icon: :unordered_list },
{ label: "Board", value: "board", icon: :appstore }
]
) %>
With name
Passing the name property to all input[type=radio] within the segmented control.
Code
<%= render Hakumi::Segmented::Component.new(
options: ["Daily", "Weekly", "Monthly"],
name: "interval"
) %>
With Icon only
Set icon without label for Segmented Item.
Code
<%= render Hakumi::Segmented::Component.new(
options: [
{ label: nil, value: "list", icon: :unordered_list, aria_label: "List view" },
{ label: nil, value: "board", icon: :appstore, aria_label: "Board view" },
{ label: nil, value: "settings", icon: :setting, aria_label: "Settings view" }
],
round: true
) %>
Segmented API
| Prop | Type | Default | Description |
|---|---|---|---|
options |
Array[String] or Array[Hash] |
[] |
Option list. Strings become both label and value. Hashes support optional keys: label:, value:, disabled:, icon:, class:. |
value |
String |
- |
Controlled selected value. |
default_value |
String |
- |
Initial selected value. |
disabled |
Boolean |
false |
Disable all options. |
block |
Boolean |
false |
Stretch to fill parent width. |
vertical |
Boolean |
false |
Render options vertically. |
round |
Boolean |
false |
Use pill-shaped segments. |
name |
String |
auto |
Shared name for input[type=radio] options. |
size |
Symbol |
:middle |
Size of items (:small, :middle, :large). |
aria_label |
String |
- |
Accessible label for the group. |
content |
Slot |
- |
Additional custom items rendered after options. |
Segmented JavaScript API (element.hakumiSegmented)
| Prop | Type | Default | Description |
|---|---|---|---|
getValue() |
Function |
- |
Returns the current selected value. |
setValue(value) |
Function |
- |
Programmatically set the selected value. |
reset() |
Function |
- |
Reset to the initial selected value. |
clear() |
Function |
- |
Clear the selected value. |
getOptions() |
Function |
- |
Returns the currently rendered options. |
setOptions(options) |
Function |
- |
Replace the option list (text-only options). |
onChange(callback) |
Function |
- |
Subscribe to value changes. |
offChange(callback) |
Function |
- |
Unsubscribe from value changes. |