Toggle Group
A segmented control of toggle items.
<togglegroup.ToggleGroup label="Alignment">
<togglegroup.ToggleGroupItem name="align" value="left" checked>Left</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align" value="center">Center</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align" value="right">Right</togglegroup.ToggleGroupItem>
</togglegroup.ToggleGroup>Installation
Run the command in the app module.
gx add toggle-groupThe command writes these files.
| File | Path in the app |
|---|---|
ToggleGroup.gx |
ui/toggle-group/ToggleGroup.gx |
ToggleGroupItem.gx |
ui/toggle-group/ToggleGroupItem.gx |
styles.go |
ui/toggle-group/styles.go |
ToggleGroup.fixtures.go |
ui/toggle-group/ToggleGroup.fixtures.go |
ToggleGroupItem.fixtures.go |
ui/toggle-group/ToggleGroupItem.fixtures.go |
Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.
package togglegroup
props {
// Variant sets the visual style of every item: Default or Outline.
Variant Variant = Default
// Size sets the height of every item: Sm, Md or Lg.
Size Size = Md
// Spacing is the gap between the items in spacing units. Zero joins the items.
Spacing int = 0
// Label is the accessible name of the group.
Label string = ""
// Class adds classes to the root element.
Class string = ""
// Children is the toggle items.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div role="group" aria-label={p.Label} data-variant={p.variant()} data-size={p.size()} data-spacing={p.spacing()} style={p.gap()} class={gx.Cx("group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md", p.Class)} {...p.Attrs}>{p.Children}</div>package togglegroup
props {
// Name is the form field name. Every item of an exclusive group has the same name.
Name string
// Value is the value the form submits when the item is checked.
Value string
// Checked selects the item for the first render.
Checked bool = false
// Multiple renders a checkbox in place of a radio, so the item toggles on its own.
Multiple bool = false
// Disabled disables the item.
Disabled bool = false
// Class adds classes to the root element.
Class string = ""
// Children is the item label.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<label class={gx.Cx("inline-flex h-9 w-auto min-w-0 shrink-0 items-center justify-center gap-2 rounded-md bg-transparent px-3 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground has-[:focus-visible]:z-10 has-[:focus-visible]:border-ring has-[:focus-visible]:ring-[3px] has-[:focus-visible]:ring-ring/50 has-[:disabled]:pointer-events-none has-[:disabled]:opacity-50 has-[:checked]:bg-accent has-[:checked]:text-accent-foreground motion-reduce:transition-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 group-data-[size=sm]/toggle-group:h-8 group-data-[size=lg]/toggle-group:h-10 group-data-[variant=outline]/toggle-group:border group-data-[variant=outline]/toggle-group:border-input group-data-[variant=outline]/toggle-group:shadow-xs group-data-[variant=outline]/toggle-group:hover:bg-accent group-data-[variant=outline]/toggle-group:hover:text-accent-foreground group-data-[spacing=0]/toggle-group:rounded-none group-data-[spacing=0]/toggle-group:first:rounded-l-md group-data-[spacing=0]/toggle-group:last:rounded-r-md group-data-[spacing=0]/toggle-group:group-data-[variant=outline]/toggle-group:border-l-0 group-data-[spacing=0]/toggle-group:group-data-[variant=outline]/toggle-group:shadow-none group-data-[spacing=0]/toggle-group:group-data-[variant=outline]/toggle-group:first:border-l", p.Class)} {...p.Attrs}>
<input type={p.inputType()} name={p.Name} value={p.Value} checked={p.Checked} disabled={p.Disabled} class="peer sr-only" />
{p.Children}
</label>package togglegroup
import (
"strconv"
"github.com/alternayte/gx"
)
// Variant is the visual style of the items of a toggle group.
type Variant string
// The variants of togglegroup.ToggleGroup.
const (
Default Variant = "default"
Outline Variant = "outline"
)
// Size is the height of the items of a toggle group.
type Size string
// The sizes of togglegroup.ToggleGroup.
const (
Sm Size = "sm"
Md Size = "md"
Lg Size = "lg"
)
// variant returns the data-variant value; a zero value is Default. The
// items read it through the group, so one prop styles every item.
func (p ToggleGroupProps) variant() string {
if p.Variant == "" {
return string(Default)
}
return string(p.Variant)
}
// size returns the data-size value; a zero value is Md.
func (p ToggleGroupProps) size() string {
if p.Size == "" {
return string(Md)
}
return string(p.Size)
}
// spacing returns the gap between the items in spacing units. Zero joins
// the items.
func (p ToggleGroupProps) spacing() int {
if p.Spacing < 0 {
return 0
}
return p.Spacing
}
// gap returns the custom property that the gap class of the group reads.
func (p ToggleGroupProps) gap() gx.Style {
return gx.Style("--gap: " + strconv.Itoa(p.spacing()))
}
// inputType returns the type of the native input: a radio for an exclusive
// choice, a checkbox when the group takes many values.
func (p ToggleGroupItemProps) inputType() string {
if p.Multiple {
return "checkbox"
}
return "radio"
}package togglegroup
import "github.com/alternayte/gx"
// align returns three exclusive items. Each fixture passes its own name:
// radios that share a name form one group across the whole gallery page.
func align(name string) gx.Node {
return gx.Frag(
ToggleGroupItem(ToggleGroupItemProps{Name: name, Value: "left", Checked: true, Children: gx.Text("Left")}),
ToggleGroupItem(ToggleGroupItemProps{Name: name, Value: "center", Children: gx.Text("Center")}),
ToggleGroupItem(ToggleGroupItemProps{Name: name, Value: "right", Children: gx.Text("Right")}),
)
}
var ToggleGroupFixtures = gx.Fixtures[ToggleGroupProps]{
"Three": {Label: "Alignment", Children: align("align")},
"Outline": {Label: "Alignment", Variant: Outline, Children: align("align-outline")},
"Spaced": {Label: "Alignment", Spacing: 2, Children: align("align-spaced")},
"OutlineSpaced": {Label: "Alignment", Variant: Outline, Spacing: 2, Children: align("align-outline-spaced")},
"Small": {Label: "Alignment", Variant: Outline, Size: Sm, Children: align("align-small")},
"Large": {Label: "Alignment", Variant: Outline, Size: Lg, Children: align("align-large")},
"Multiple": {Label: "Format", Variant: Outline, Children: gx.Frag(
ToggleGroupItem(ToggleGroupItemProps{Name: "bold", Value: "on", Multiple: true, Checked: true, Children: gx.Text("Bold")}),
ToggleGroupItem(ToggleGroupItemProps{Name: "italic", Value: "on", Multiple: true, Checked: true, Children: gx.Text("Italic")}),
ToggleGroupItem(ToggleGroupItemProps{Name: "strike", Value: "on", Multiple: true, Disabled: true, Children: gx.Text("Strike")}),
)},
}package togglegroup
import "github.com/alternayte/gx"
var ToggleGroupItemFixtures = gx.Fixtures[ToggleGroupItemProps]{
"Checked": {Name: "align-demo", Value: "left", Checked: true, Children: gx.Text("Left")},
"Disabled": {Name: "align-disabled", Value: "left", Disabled: true, Children: gx.Text("Left")},
}
// ToggleGroupItemWrap renders the item inside a group, as a page uses it.
func ToggleGroupItemWrap(n gx.Node) gx.Node {
return ToggleGroup(ToggleGroupProps{Label: "Alignment", Children: n})
}The theme must define these tokens: --input, --muted, --muted-foreground, --accent, --accent-foreground, --ring.
Usage
<togglegroup.ToggleGroup label="Alignment" variant={togglegroup.Outline}>
<togglegroup.ToggleGroupItem name="align" value="left" checked={true}>Left</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align" value="center">Center</togglegroup.ToggleGroupItem>
</togglegroup.ToggleGroup>The group is a set of styled radio inputs, so it works without JavaScript.
Variant and Size on the group style every item.
Spacing is the gap between the items in spacing units. Zero joins the items and shares their borders.
Set Multiple on every item to make each item an independent checkbox.
Examples
ToggleGroup: Three
<togglegroup.ToggleGroup label="Alignment">
<togglegroup.ToggleGroupItem name="align" value="left" checked>Left</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align" value="center">Center</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align" value="right">Right</togglegroup.ToggleGroupItem>
</togglegroup.ToggleGroup>ToggleGroup: Outline
<togglegroup.ToggleGroup label="Alignment" variant={togglegroup.Outline}>
<togglegroup.ToggleGroupItem name="align-outline" value="left" checked>Left</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align-outline" value="center">Center</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align-outline" value="right">Right</togglegroup.ToggleGroupItem>
</togglegroup.ToggleGroup>ToggleGroup: Spaced
<togglegroup.ToggleGroup label="Alignment" spacing={2}>
<togglegroup.ToggleGroupItem name="align-spaced" value="left" checked>Left</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align-spaced" value="center">Center</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align-spaced" value="right">Right</togglegroup.ToggleGroupItem>
</togglegroup.ToggleGroup>ToggleGroup: Outline spaced
<togglegroup.ToggleGroup label="Alignment" variant={togglegroup.Outline} spacing={2}>
<togglegroup.ToggleGroupItem name="align-outline-spaced" value="left" checked>Left</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align-outline-spaced" value="center">Center</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align-outline-spaced" value="right">Right</togglegroup.ToggleGroupItem>
</togglegroup.ToggleGroup>ToggleGroup: Small
<togglegroup.ToggleGroup label="Alignment" variant={togglegroup.Outline} size={togglegroup.Sm}>
<togglegroup.ToggleGroupItem name="align-small" value="left" checked>Left</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align-small" value="center">Center</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align-small" value="right">Right</togglegroup.ToggleGroupItem>
</togglegroup.ToggleGroup>ToggleGroup: Large
<togglegroup.ToggleGroup label="Alignment" variant={togglegroup.Outline} size={togglegroup.Lg}>
<togglegroup.ToggleGroupItem name="align-large" value="left" checked>Left</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align-large" value="center">Center</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="align-large" value="right">Right</togglegroup.ToggleGroupItem>
</togglegroup.ToggleGroup>ToggleGroup: Multiple
<togglegroup.ToggleGroup label="Format" variant={togglegroup.Outline}>
<togglegroup.ToggleGroupItem name="bold" value="on" multiple checked>Bold</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="italic" value="on" multiple checked>Italic</togglegroup.ToggleGroupItem>
<togglegroup.ToggleGroupItem name="strike" value="on" multiple disabled>Strike</togglegroup.ToggleGroupItem>
</togglegroup.ToggleGroup>ToggleGroupItem: Checked
<togglegroup.ToggleGroupItem name="align-demo" value="left" checked>Left</togglegroup.ToggleGroupItem>ToggleGroupItem: Disabled
<togglegroup.ToggleGroupItem name="align-disabled" value="left" disabled>Left</togglegroup.ToggleGroupItem>API reference
A tag sets a prop by its name with a lower-case first letter: Class is class.
togglegroup.ToggleGroup
| Prop | Type | Default | Description |
|---|---|---|---|
Variant |
Variant |
Default |
Variant sets the visual style of every item: Default or Outline. |
Size |
Size |
Md |
Size sets the height of every item: Sm, Md or Lg. |
Spacing |
int |
0 |
Spacing is the gap between the items in spacing units. Zero joins the items. |
Label |
string |
"" |
Label is the accessible name of the group. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the toggle items. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
togglegroup.ToggleGroupItem
| Prop | Type | Default | Description |
|---|---|---|---|
Name |
string |
Required | Name is the form field name. Every item of an exclusive group has the same name. |
Value |
string |
Required | Value is the value the form submits when the item is checked. |
Checked |
bool |
false |
Checked selects the item for the first render. |
Multiple |
bool |
false |
Multiple renders a checkbox in place of a radio, so the item toggles on its own. |
Disabled |
bool |
false |
Disabled disables the item. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the item label. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
Do and do not
Do
- Give every item of an exclusive group the same
Name. - Set
Checkedon exactly one item of an exclusive group. - Give the group a
Label.
Don't
- Do not mix exclusive items and
Multipleitems in one group. - Do not mix two groups under one name.
Keyboard
| Key | Action |
|---|---|
| Tab | Moves focus to the checked item. With Multiple, moves focus to each item. |
| Arrow keys | Moves the choice and selects it. |
| Space | Selects the focused item. With Multiple, toggles it. |