Radio Group
A group of exclusive choices.
<radiogroup.RadioGroup label="Plan">
<radiogroup.RadioGroupItem name="plan" value="free" checked label="Free" />
<radiogroup.RadioGroupItem name="plan" value="pro" label="Pro" />
</radiogroup.RadioGroup>Installation
Run the command in the app module.
gx add radio-groupThe command also installs icons.
The command writes these files.
| File | Path in the app |
|---|---|
RadioGroup.gx |
ui/radio-group/RadioGroup.gx |
RadioGroupItem.gx |
ui/radio-group/RadioGroupItem.gx |
RadioGroup.fixtures.go |
ui/radio-group/RadioGroup.fixtures.go |
styles.go |
ui/radio-group/styles.go |
RadioGroupItem.fixtures.go |
ui/radio-group/RadioGroupItem.fixtures.go |
Install icons first.
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 radiogroup
props {
// Orientation sets the layout direction: Vertical or Horizontal.
Orientation Orientation = Vertical
// Label is the accessible name of the group.
Label string = ""
// Class adds classes to the root element.
Class string = ""
// Children is the radio items.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<div role="radiogroup" aria-label={p.Label} aria-orientation={p.orientation()} class={gx.Cx("grid gap-3", orientationClass[p.orientation()], p.Class)} {...p.Attrs}>{p.Children}</div>package radiogroup
import "github.com/alternayte/gx/registry/icons"
props {
// Name is the form field name. Every item of one 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
// Disabled disables the item.
Disabled bool = false
// Invalid sets aria-invalid on the input and shows the error style.
Invalid bool = false
// Label is the text beside the radio. An empty value renders no text.
Label string = ""
// Class adds classes to the root element.
Class string = ""
// Children is content beside the radio, after the label text.
Children gx.Node = nil
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<label class={gx.Cx("flex items-center gap-2 text-sm leading-none font-medium select-none", p.Class)} {...p.Attrs}>
<input type="radio" name={p.Name} value={p.Value} checked={p.Checked} disabled={p.Disabled} aria-invalid={p.invalid()} class="peer sr-only" />
<span aria-hidden="true" class="relative aspect-square size-4 shrink-0 rounded-full border border-input text-primary shadow-xs transition-[color,box-shadow] outline-none peer-focus-visible:border-ring peer-focus-visible:ring-[3px] peer-focus-visible:ring-ring/50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50 peer-aria-invalid:border-destructive peer-aria-invalid:ring-destructive/20 dark:bg-input/30 dark:peer-aria-invalid:ring-destructive/40 motion-reduce:transition-none [&>svg]:opacity-0 peer-checked:[&>svg]:opacity-100">
<icons.Circle class="absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 [&>circle]:fill-primary" />
</span>
if p.Label != "" {
<span class="peer-disabled:cursor-not-allowed peer-disabled:opacity-50">{p.Label}</span>
}
if p.Children != nil {
<span class="peer-disabled:cursor-not-allowed peer-disabled:opacity-50">{p.Children}</span>
}
</label>package radiogroup
import "github.com/alternayte/gx"
// Each fixture has its own name: radios that share a name form one group
// across the whole gallery page, and only one of them stays checked.
var RadioGroupFixtures = gx.Fixtures[RadioGroupProps]{
"Vertical": {
Label: "Plan",
Children: gx.Frag(
RadioGroupItem(RadioGroupItemProps{Name: "plan", Value: "free", Checked: true, Label: "Free"}),
RadioGroupItem(RadioGroupItemProps{Name: "plan", Value: "pro", Label: "Pro"}),
),
},
"Horizontal": {
Label: "Size",
Orientation: Horizontal,
Children: gx.Frag(
RadioGroupItem(RadioGroupItemProps{Name: "size", Value: "s", Checked: true, Label: "Small"}),
RadioGroupItem(RadioGroupItemProps{Name: "size", Value: "m", Label: "Medium"}),
),
},
}package radiogroup
import "github.com/alternayte/gx"
// Orientation is the layout direction of a radio group.
type Orientation string
// The orientations of radiogroup.RadioGroup.
const (
Vertical Orientation = "vertical"
Horizontal Orientation = "horizontal"
)
var orientationClass = gx.Enum[Orientation]{
Vertical: "grid-cols-1",
Horizontal: "grid-flow-col auto-cols-max gap-4",
}
// orientation returns the orientation of one group; a zero value is
// Vertical.
func (p RadioGroupProps) orientation() Orientation {
if p.Orientation == "" {
return Vertical
}
return p.Orientation
}
// invalid returns the aria-invalid value of the input.
func (p RadioGroupItemProps) invalid() string {
if p.Invalid {
return "true"
}
return "false"
}package radiogroup
import "github.com/alternayte/gx"
var RadioGroupItemFixtures = gx.Fixtures[RadioGroupItemProps]{
"Unchecked": {Name: "item-unchecked", Value: "free", Label: "Free"},
"Checked": {Name: "item-checked", Value: "pro", Checked: true, Label: "Pro"},
"Disabled": {Name: "item-disabled", Value: "pro", Checked: true, Disabled: true, Label: "Pro"},
"Invalid": {Name: "item-invalid", Value: "pro", Invalid: true, Label: "Pro"},
}The theme must define these tokens: --primary, --input, --ring, --destructive.
Usage
<radiogroup.RadioGroup label="Plan">
<radiogroup.RadioGroupItem name="plan" value="free" checked={true} label="Free" />
<radiogroup.RadioGroupItem name="plan" value="pro" label="Pro" />
</radiogroup.RadioGroup>Each item is a native radio input behind a styled circle.
Disabled and Invalid set the state of the input.
Examples
RadioGroup: Vertical
<radiogroup.RadioGroup label="Plan">
<radiogroup.RadioGroupItem name="plan" value="free" checked label="Free" />
<radiogroup.RadioGroupItem name="plan" value="pro" label="Pro" />
</radiogroup.RadioGroup>RadioGroup: Horizontal
<radiogroup.RadioGroup label="Size" orientation={radiogroup.Horizontal}>
<radiogroup.RadioGroupItem name="size" value="s" checked label="Small" />
<radiogroup.RadioGroupItem name="size" value="m" label="Medium" />
</radiogroup.RadioGroup>RadioGroupItem: Unchecked
<radiogroup.RadioGroupItem name="item-unchecked" value="free" label="Free" />RadioGroupItem: Checked
<radiogroup.RadioGroupItem name="item-checked" value="pro" checked label="Pro" />RadioGroupItem: Disabled
<radiogroup.RadioGroupItem name="item-disabled" value="pro" checked disabled label="Pro" />RadioGroupItem: Invalid
<radiogroup.RadioGroupItem name="item-invalid" value="pro" invalid label="Pro" />API reference
A tag sets a prop by its name with a lower-case first letter: Class is class.
radiogroup.RadioGroup
| Prop | Type | Default | Description |
|---|---|---|---|
Orientation |
Orientation |
Vertical |
Orientation sets the layout direction: Vertical or Horizontal. |
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 radio items. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
radiogroup.RadioGroupItem
| Prop | Type | Default | Description |
|---|---|---|---|
Name |
string |
"" |
Name is the form field name. Every item of one group has the same name. |
Value |
string |
"" |
Value is the value the form submits when the item is checked. |
Checked |
bool |
false |
Checked selects the item for the first render. |
Disabled |
bool |
false |
Disabled disables the item. |
Invalid |
bool |
false |
Invalid sets aria-invalid on the input and shows the error style. |
Label |
string |
"" |
Label is the text beside the radio. An empty value renders no text. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
nil |
Children is content beside the radio, after the label text. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
Do and do not
Do
- Give every item the same
Name. - Set
Checkedon exactly one item. - Give the group a
Label.
Don't
- Do not use a radio group for a boolean. Use a checkbox or a switch.
- Do not mix two names in one group.
Keyboard
| Key | Action |
|---|---|
| Tab | Moves focus to the checked item. |
| Arrow keys | Moves the choice and selects it. |
| Space | Selects the focused item. |