A toggle button allows to toggle a selection on or off, for example switching between two states or modes.
Unselected, it reads as an outlined button — ink and border only. Selected, it
fills with its color and switches to the matching contrast ink; hovering
and pressing deepen that fill one step at a time, the same ramp a filled
Button uses, so the label stays readable in every state.
import { ToggleButton } from 'frontile';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { ToggleButton } from 'frontile';
import { StarIcon } from 'site/components/icons';
export default class Example extends Component {
@tracked
isSelected = false;
@action
onChange(value: boolean): void {
this.isSelected = value;
}
<template>
<ToggleButton
@isSelected={{this.isSelected}}
@onChange={{this.onChange}}
aria-label='Favourite'
>
<StarIcon />
</ToggleButton>
</template>
}
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { fn } from '@ember/helper';
import { ToggleButton } from 'frontile';
export default class Example extends Component {
@tracked
isSelected = {
default: false,
primary: false,
secondary: false,
tertiary: false,
success: false,
warning: false,
danger: false
};
@action
onChange(ty: keyof typeof this.isSelected, value: boolean): void {
this.isSelected[ty] = value;
this.isSelected = { ...this.isSelected };
}
<template>
{{#each-in this.isSelected as |key val|}}
<ToggleButton
@isSelected={{val}}
@onChange={{(fn this.onChange key)}}
@color={{key}}
>
Toggle
</ToggleButton>
{{/each-in}}
</template>
}
import { ToggleButton } from 'frontile';
<template>
<ToggleButton @size='xs'>ToggleButton</ToggleButton>
<ToggleButton @size='sm'>ToggleButton</ToggleButton>
<ToggleButton @size='md'>ToggleButton</ToggleButton>
<ToggleButton @size='lg'>ToggleButton</ToggleButton>
<ToggleButton @size='xl'>ToggleButton</ToggleButton>
</template>
You can pass the attribute disabled to disable a toggle button.
import { ToggleButton } from 'frontile';
<template>
<div>
<ToggleButton @color='neutral' disabled>ToggleButton</ToggleButton>
<ToggleButton @color='primary' disabled>Primary</ToggleButton>
<ToggleButton @color='secondary' disabled>Secondary</ToggleButton>
<ToggleButton @color='tertiary' disabled>Tertiary</ToggleButton>
<ToggleButton @color='success' disabled>Success</ToggleButton>
<ToggleButton @color='warning' disabled>Warning</ToggleButton>
<ToggleButton @color='danger' disabled>Danger</ToggleButton>
</div>
</template>
ToggleButton renders a native <button> carrying aria-pressed, which is what
turns it from a button into a toggle: assistive technology announces the label
followed by its state, and announces the change when it flips.
| Key | Behaviour |
|---|---|
Tab |
Moves focus to the toggle. Disabled toggles are skipped. |
Enter |
Toggles it, firing @onChange with the new value. |
Space |
Toggles it, firing @onChange with the new value. |
aria-pressed tracks @isSelected, which the component does not own. Always
pair it with an @onChange that writes the new value back: without one the
toggle looks pressed to the eye for as long as the pointer is down, but never
reports a state change.
An icon with no text leaves the toggle unnamed, so the state is announced with
nothing to attach it to. Pass aria-label, as the Usage demo does.
The label should name the control, not the action — "Bold", not "Make bold" —
because aria-pressed already conveys whether it is on. A label that changes
with the state ("Mute" / "Unmute") duplicates that and contradicts it half the
time; if you want changing labels, use a plain Button and no aria-pressed.
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { fn } from '@ember/helper';
import { ToggleButton } from 'frontile';
export default class Example extends Component {
@tracked format: Record<string, boolean> = {
Bold: false,
Italic: false,
Underline: false
};
onChange = (key: string, value: boolean): void => {
this.format = { ...this.format, [key]: value };
};
<template>
<div class='flex items-center gap-2'>
{{#each-in this.format as |key selected|}}
<ToggleButton
@isSelected={{selected}}
@onChange={{fn this.onChange key}}
@color='primary'
>
{{key}}
</ToggleButton>
{{/each-in}}
</div>
</template>
}
Use the plain HTML disabled attribute to disable a toggle; there is no
@isDisabled argument.
Element: HTMLButtonElement
| Name | Type | Default | Description |
|---|---|---|---|
appearance
Deprecated
|
enum
|
- |
Deprecated. Use `variant`. `default` is now `solid`, `outlined` is `outline`, and `minimal` is `plain`. |
class
|
string
|
- | Custom class name, it will override the default ones using Tailwind Merge library. |
color
|
enum
|
- | The color of the button |
intent
Deprecated
|
enum
|
- |
Deprecated. Use `color`. `default` is now `neutral`. |
isInGroup
|
boolean
|
- | If button is part of a group. Most of the time, this is automatically set when using the ButtonGroup component. |
isSelected
|
boolean
|
false
|
If the button is currently selected |
onChange
|
function
|
- | Callback when the buttle is toggled |
size
|
enum
|
- | The size of the button |
variant
|
enum
|
'solid'
|
The button variant. |
| Name | Type | Default | Description |
|---|---|---|---|
default
*
|
Array
|
- |