Coordinated group of toggle buttons for single or multi-select interactions.
toggle_group/1 groups multiple toggle_group_item/1 buttons into a widget
with role="group". Items compute their aria-pressed state automatically
based on the group's current :value, so you never need to pass pressed
manually to each item.
Sub-components
| Function | Purpose |
|---|---|
toggle_group/1 | Container with role="group", coordinates item state |
toggle_group_item/1 | Individual button whose pressed state is derived from group value |
Selection modes
Single select (type="single")
Only one item can be active at a time. The group value is a string (or nil
for no selection). Use for mutually exclusive choices like text alignment,
view mode, or sort direction:
<.toggle_group type="single" value={@align} phx-change="set_align">
<.toggle_group_item value="left">
<.icon name="align-left" size="sm" />
</.toggle_group_item>
<.toggle_group_item value="center">
<.icon name="align-center" size="sm" />
</.toggle_group_item>
<.toggle_group_item value="right">
<.icon name="align-right" size="sm" />
</.toggle_group_item>
</.toggle_group>Multi-select (type="multiple")
Multiple items can be active simultaneously. The group value is a list of strings. Use for text formatting (bold + italic), filter chips, or feature flags:
<.toggle_group type="multiple" value={@formats} phx-change="set_format">
<.toggle_group_item value="bold">B</.toggle_group_item>
<.toggle_group_item value="italic">I</.toggle_group_item>
<.toggle_group_item value="underline">U</.toggle_group_item>
<.toggle_group_item value="strikethrough">S</.toggle_group_item>
</.toggle_group>Using :let context
When nesting items inside the group slot, the parent passes context via
:let. Items use {group} spread to receive group_value, group_type,
variant, and size from the parent automatically:
<.toggle_group :let={group} type="single" value={@view_mode} variant="outline">
<.toggle_group_item value="grid" {group}><.icon name="grid" /></.toggle_group_item>
<.toggle_group_item value="list" {group}><.icon name="list" /></.toggle_group_item>
<.toggle_group_item value="table" {group}><.icon name="table" /></.toggle_group_item>
</.toggle_group>View mode switcher example
defmodule MyAppWeb.ProductsLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket, view_mode: "grid", filters: [])}
end
def handle_event("set_view", %{"value" => mode}, socket) do
{:noreply, assign(socket, view_mode: mode)}
end
def handle_event("set_filter", %{"value" => filters}, socket) do
{:noreply, assign(socket, filters: filters)}
end
end
<%!-- In the template --%>
<.toggle_group type="single" value={@view_mode} phx-change="set_view" variant="outline">
<.toggle_group_item value="grid">Grid</.toggle_group_item>
<.toggle_group_item value="list">List</.toggle_group_item>
</.toggle_group>Text formatting toolbar (multi-select)
<.toggle_group type="multiple" value={@active_formats} phx-change="set_format" size="sm">
<.toggle_group_item value="bold" aria-label="Bold">B</.toggle_group_item>
<.toggle_group_item value="italic" aria-label="Italic">I</.toggle_group_item>
<.toggle_group_item value="underline" aria-label="Underline">U</.toggle_group_item>
<.toggle_group_item value="strikethrough" aria-label="Strikethrough">S</.toggle_group_item>
</.toggle_group>Variants and sizes
Both the toggle_group/1 and toggle_group_item/1 accept :variant and
:size. Setting them on the group propagates to all items via the :let
context — no need to set them on every item individually.
- Variants:
"default"(ghost-like),"outline"(bordered) - Sizes:
"sm","default","lg"
Summary
Functions
Renders a group container that coordinates a set of toggle items.
Renders a single pressable item within a toggle_group/1.
Functions
Renders a group container that coordinates a set of toggle items.
Exposes group context via :let so items can compute their pressed state
and inherit variant/size without repeating those attributes on each item:
<.toggle_group :let={group} type="single" value={@align} variant="outline">
<.toggle_group_item value="left" {group}><.icon name="align-left" /></.toggle_group_item>
<.toggle_group_item value="center" {group}><.icon name="align-center" /></.toggle_group_item>
<.toggle_group_item value="right" {group}><.icon name="align-right" /></.toggle_group_item>
</.toggle_group>The {group} spread is equivalent to passing:
group_value={group.group_value} group_type={group.group_type} variant={group.variant} size={group.size}
Examples
<%!-- Single select — text alignment --%>
<.toggle_group type="single" value={@align} phx-change="set_align">
<.toggle_group_item value="left">Left</.toggle_group_item>
<.toggle_group_item value="center">Center</.toggle_group_item>
<.toggle_group_item value="right">Right</.toggle_group_item>
</.toggle_group>
<%!-- Multi-select — active filters --%>
<.toggle_group type="multiple" value={@active_filters} phx-change="toggle_filter" size="sm" variant="outline">
<.toggle_group_item value="in_stock">In stock</.toggle_group_item>
<.toggle_group_item value="on_sale">On sale</.toggle_group_item>
<.toggle_group_item value="new_arrivals">New arrivals</.toggle_group_item>
</.toggle_group>Attributes
type(:string) - Selection mode:"single"— only one item can be active;:valueis a string ornil"multiple"— several items can be active;:valueis a list of strings
Defaults to
"single". Must be one of"single", or"multiple".value(:any) - Currently selected value(s). Type depends on:type:- For
"single": a string matching one item's:value, ornilfor no selection - For
"multiple": a list of strings, e.g.["bold", "italic"]
This is passed down to each item via the slot context so items can compute their own
pressedstate.Defaults to
nil.- For
variant(:string) - Visual style propagated to all items:"default"— ghost-like, transparent background"outline"— bordered withborder-input
Defaults to
"default". Must be one of"default", or"outline".size(:string) - Button size propagated to all items:"sm"—h-9 px-2.5 text-xs(compact toolbars)"default"—h-10 px-3"lg"—h-11 px-5
Defaults to
"default". Must be one of"default","sm", or"lg".class(:string) - Additional CSS classes applied to the group container<div>. Defaults tonil.Global attributes are accepted. HTML attributes forwarded to the group
<div>. Typically used forphx-changeto notify the LiveView when the selection changes.
Slots
inner_block(required) - One or moretoggle_group_item/1components. Use:let={group}on the parent to capture the context map, then spread{group}onto each item to propagategroup_value,group_type,variant, andsize.
Renders a single pressable item within a toggle_group/1.
The :pressed state is computed at render time from :group_type and
:group_value, so the template stays declarative. In normal usage, pass
context from the parent via {group} spread:
<.toggle_group :let={group} type="multiple" value={@formats}>
<.toggle_group_item value="bold" {group}>B</.toggle_group_item>
<.toggle_group_item value="italic" {group}>I</.toggle_group_item>
</.toggle_group>Examples
<%!-- Inside a single-select group --%>
<.toggle_group :let={g} type="single" value={@mode}>
<.toggle_group_item value="grid" {g}><.icon name="grid" /></.toggle_group_item>
<.toggle_group_item value="list" {g}><.icon name="list" /></.toggle_group_item>
</.toggle_group>
<%!-- Manual usage (no group context) --%>
<.toggle_group_item
value="bold"
group_value={@active_formats}
group_type="multiple"
>
Bold
</.toggle_group_item>
<%!-- Disabled item within a group --%>
<.toggle_group :let={g} type="single" value={@mode}>
<.toggle_group_item value="grid" {g}>Grid</.toggle_group_item>
<.toggle_group_item value="table" {g} disabled>Table (coming soon)</.toggle_group_item>
</.toggle_group>Attributes
value(:string) (required) - The value this item represents within the group. Fortype="single", this string is compared against the group value. Fortype="multiple", membership in the group value list is checked.group_value(:any) - The group's current selected value(s). Used to compute this item'spressedstate. In typical usage, this is passed via the{group}spread from the parent's:letcontext — you do not need to set it manually.Defaults to
nil.group_type(:string) - The parent group's selection type. Used for thepressedcalculation:"single": pressed whengroup_value == value"multiple": pressed whenvalue in group_valueInherited from the group context via{group}spread in typical usage.
Defaults to
"single". Must be one of"single", or"multiple".variant(:string) - Visual style of the button. Normally inherited from the group via{group}spread. Override per-item only when you need a different style than the group default.Defaults to
"default". Must be one of"default", or"outline".size(:string) - Button size. Normally inherited from the group via{group}spread. Override per-item only when individual sizing is needed.Defaults to
"default". Must be one of"default","sm", or"lg".disabled(:boolean) - Whentrue, disables this item. It becomes non-interactive and renders at 50% opacity. Defaults tofalse.class(:string) - Additional CSS classes applied to the<button>element viacn/1. Defaults tonil.Global attributes are accepted. HTML attributes forwarded to the
<button>element. Typically used for per-itemphx-clickhandlers when items need individual event handling rather than a group-levelphx-change. Supports all globals plus:["phx-click", "phx-value"].
Slots
inner_block(required) - Item content — typically a short text label or an icon component.