Packages
mishka_chelekom
0.0.9
0.0.10-alpha.5
0.0.10-alpha.4
0.0.10-alpha.3
0.0.10-alpha.2
0.0.10-alpha.1
0.0.9
0.0.9-rc.2
0.0.9-rc.1
0.0.9-beta.5
0.0.9-beta.4
0.0.9-beta.3
0.0.9-beta.2
0.0.9-beta.1
0.0.9-alpha.20
0.0.9-alpha.18
0.0.9-alpha.17
0.0.9-alpha.16
0.0.9-alpha.15
0.0.9-alpha.14
0.0.9-alpha.13
0.0.9-alpha.12
0.0.9-alpha.11
0.0.9-alpha.10
0.0.9-alpha.9
0.0.9-alpha.8
0.0.9-alpha.7
0.0.9-alpha.6
0.0.9-alpha.5
0.0.9-alpha.4
0.0.9-alpha.3
0.0.9-alpha.2
0.0.9-alpha.1
0.0.8
0.0.8-rc.2
0.0.8-rc.1
0.0.8-beta.5
0.0.8-beta.4
0.0.8-beta.3
0.0.8-beta.2
0.0.8-beta.1
0.0.8-alpha.4
0.0.8-alpha.3
0.0.8-alpha.2
0.0.8-alpha.1
0.0.7
0.0.6
0.0.6-alpha.2
0.0.6-alpha.1
0.0.5
0.0.5-beta.2
0.0.5-beta.1
0.0.5-alpha.12
0.0.5-alpha.11
0.0.5-alpha.10
0.0.5-alpha.9
0.0.5-alpha.8
0.0.5-alpha.7
0.0.5-alpha.6
0.0.5-alpha.5
0.0.5-alpha.4
0.0.5-alpha.3
0.0.5-alpha.2
0.0.5-alpha.1
0.0.4
0.0.4-beta.3
0.0.4-beta.2
0.0.4-beta.1
0.0.4-alpha.9
0.0.4-alpha.8
0.0.4-alpha.7
0.0.4-alpha.6
0.0.4-alpha.5
0.0.4-alpha.4
0.0.4-alpha.3
0.0.4-alpha.2
0.0.4-alpha.1
0.0.3
0.0.3-alpha.3
0.0.3-alpha.2
0.0.3-alpha.1
0.0.2
0.0.2-rc.2
0.0.2-rc.1
0.0.2-beta.4
0.0.2-beta.3
0.0.2-beta.2
0.0.2-beta.1
0.0.2-alpha.3
0.0.2-alpha.2
0.0.2-alpha.1
0.0.1
Mishka Chelekom is a fully featured components and UI kit library for Phoenix & Phoenix LiveView
Current section
Files
Jump to
Current section
Files
priv/headless/toggle_group.eex
defmodule <%= @module %> do
@moduledoc """
Headless **toggle group** — a coordinated row of toggle buttons, single- or multi-select
(Base UI parity).
One `ToggleGroup` engine owns the group: roving tabindex (arrow keys along the `orientation` +
Home/End, looping when `loop`), and the pressed state of every item. Without `multiple` it is
single-select — pressing an item presses only it, and pressing the pressed item deselects it (the
group may be empty), like Base UI. With `multiple`, several may be pressed. Each item reflects
`aria-pressed` + `data-pressed`; the pressed values mirror into hidden inputs (single → `name`,
multiple → `name[]`) and dispatch `input` so `<.form>` reacts; `on_change` pushes `{value}`.
Options mirror Base UI: `value`/`default` (the pressed values — a list, or a single string for
single-select), `multiple`, `disabled`, `orientation` (horizontal | vertical), `loop`, plus
`name`/`form`/`on_change`. State attributes: root `data-orientation`, `data-multiple`,
`data-disabled`; items `data-pressed`, `data-disabled`. Style via `chelekom-toggle-group*`.
WAI-ARIA APG: https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/
"""
use Phoenix.Component
@doc type: :component
attr :id, :string, required: true
attr :name, :string, default: nil, doc: "Form field name (single → name, multiple → name[])"
attr :value, :any, default: nil, doc: "Pressed value(s) — a list, or a single string (Phoenix form value)"
attr :multiple, :boolean, default: false, doc: "Allow several items pressed at once (data-multiple)"
attr :disabled, :boolean, default: false, doc: "Disable the whole group (data-disabled)"
attr :orientation, :string, default: "horizontal", doc: "horizontal | vertical (arrow-key axis)"
attr :loop, :boolean, default: true, doc: "Loop arrow-key focus past the ends"
attr :form, :string, default: nil, doc: "Form id owning the hidden input(s)"
attr :on_change, :string, default: nil, doc: "LiveView event pushed on change ({value})"
attr :class, :any, default: nil
attr :rest, :global
slot :item, required: true, doc: "A toggle button" do
attr :value, :string, doc: "The value this toggle represents"
attr :disabled, :boolean, doc: "Disable just this item"
attr :class, :any, doc: "Additional CSS classes for this item's button (data-part=item)"
attr :"aria-label", :string, doc: "Accessible label for this item's button"
end
def <%= @component_prefix %>toggle_group(assigns) do
values =
cond do
is_list(assigns.value) -> assigns.value
assigns.value in [nil, ""] -> []
true -> [assigns.value]
end
# The tabbable entry is the first pressed-and-enabled item, else the first enabled one.
tabbable =
Enum.find_index(assigns.item, &(&1[:value] in values and !(&1[:disabled] || assigns.disabled))) ||
Enum.find_index(assigns.item, &(!(&1[:disabled] || assigns.disabled))) || 0
assigns = assign(assigns, values: values, tabbable: tabbable)
~H"""
<div
id={@id}
phx-hook="ToggleGroup"
role="group"
data-orientation={@orientation}
data-multiple={@multiple}
data-disabled={@disabled}
data-loop={@loop}
data-name={@name}
data-on-change={@on_change}
aria-orientation={@orientation}
aria-disabled={@disabled && "true"}
class={["chelekom-toggle-group", @class]}
{@rest}
>
<span data-part="value-inputs" class="chelekom-sr-only">
<%%= for v <- @values do %>
<input :if={@name} type="hidden" name={if @multiple, do: "#{@name}[]", else: @name} value={v} form={@form} />
<%% end %>
<input :if={@name && @values == [] && !@multiple} type="hidden" name={@name} value="" form={@form} />
</span>
<button
:for={{item, i} <- Enum.with_index(@item)}
type="button"
id={"#{@id}-item-#{i}"}
role="button"
data-part="item"
data-value={item[:value]}
aria-pressed={to_string(item[:value] in @values)}
aria-disabled={(@disabled || item[:disabled]) && "true"}
disabled={@disabled || item[:disabled]}
data-pressed={item[:value] in @values}
data-disabled={@disabled || item[:disabled]}
tabindex={if i == @tabbable, do: "0", else: "-1"}
aria-label={item[:"aria-label"]}
class={["chelekom-toggle-group__item", item[:class]]}
>
{render_slot(item)}
</button>
</div>
"""
end
end