Toggle
A two-state button that can be either on or off.
Loading...
<twig:Toggle variant="outline" size="sm" aria-label="Toggle bookmark">
<twig:ux:icon name="lucide:bookmark" class="group-data-[state=on]/toggle:fill-current" />
Bookmark
</twig:Toggle>
Installation
Note
Available since UX Toolkit 2.35.
bin/console ux:install toggle --kit shadcn
That's it!
Install the following Composer dependencies:
composer require twig/extra-bundle twig/html-extra:^3.12.0 tales-from-a-dev/twig-tailwind-extra:^1.0.0
Copy the following file(s) into your Symfony app:
assets/controllers/toggle_controller.js
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static values = { pressed: Boolean };
connect() {
if (!this.hasPressedValue) {
this.pressedValue = this.element.getAttribute('aria-pressed') === 'true';
}
this.updateState();
}
toggle() {
this.pressedValue = !this.pressedValue;
}
pressedValueChanged() {
this.updateState();
}
updateState() {
const pressed = this.pressedValue;
this.element.setAttribute('aria-pressed', String(pressed));
this.element.dataset.state = pressed ? 'on' : 'off';
}
}
templates/components/Toggle.html.twig
{# @prop variant 'default'|'outline' The visual style variant. Defaults to `default` #}
{# @prop size 'default'|'sm'|'lg' The toggle size. Defaults to `default` #}
{# @prop pressed boolean Whether the toggle is initially pressed. Defaults to `false` #}
{# @block content The toggle label and/or icon #}
{%- props variant = 'default', size = 'default', pressed = false -%}
{%- set style = html_cva(
base: "group/toggle inline-flex items-center justify-center gap-1 rounded-lg text-sm font-medium whitespace-nowrap transition-all outline-none hover:bg-muted hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-pressed:bg-muted data-[state=on]:bg-muted dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
variants: {
variant: {
default: 'bg-transparent',
outline: 'border border-input bg-transparent hover:bg-muted',
},
size: {
default: 'h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
sm: "h-7 min-w-7 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
lg: 'h-9 min-w-9 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',
},
},
default_variant: {
variant: 'default',
size: 'default',
},
) -%}
<button
type="button"
class="{{ style.apply({variant: variant, size: size}, attributes.render('class'))|tailwind_merge }}"
{{ attributes.defaults({
'data-slot': 'toggle',
'data-controller': 'toggle',
'data-action': 'click->toggle#toggle',
'aria-pressed': pressed ? 'true' : 'false',
'data-state': pressed ? 'on' : 'off',
}) }}
>
{%- block content %}{% endblock -%}
</button>
Happy coding!
Usage
<twig:Toggle>
Toggle
</twig:Toggle>
Examples
Outline
Use variant="outline" for an outline style.
Loading...
<div class="flex flex-wrap items-center gap-2">
<twig:Toggle variant="outline" aria-label="Toggle italic">
<twig:ux:icon name="lucide:italic" />
Italic
</twig:Toggle>
<twig:Toggle variant="outline" aria-label="Toggle bold">
<twig:ux:icon name="lucide:bold" />
Bold
</twig:Toggle>
</div>
With Text
Loading...
<twig:Toggle aria-label="Toggle italic">
<twig:ux:icon name="lucide:italic" />
Italic
</twig:Toggle>
Size
Use the size prop to change the size of the toggle.
Loading...
<div class="flex flex-wrap items-center gap-2">
<twig:Toggle variant="outline" aria-label="Toggle small" size="sm">
Small
</twig:Toggle>
<twig:Toggle variant="outline" aria-label="Toggle default" size="default">
Default
</twig:Toggle>
<twig:Toggle variant="outline" aria-label="Toggle large" size="lg">
Large
</twig:Toggle>
</div>
Disabled
Loading...
<div class="flex flex-wrap items-center gap-2">
<twig:Toggle aria-label="Toggle disabled" disabled>
Disabled
</twig:Toggle>
<twig:Toggle variant="outline" aria-label="Toggle disabled outline" disabled>
Disabled
</twig:Toggle>
</div>
RTL
To enable RTL support, set the dir="rtl" attribute on the root element.
Loading...
<div class="flex flex-col gap-8">
{# Arabic #}
<twig:Toggle variant="outline" size="sm" aria-label="Toggle bookmark" dir="rtl">
<twig:ux:icon name="lucide:bookmark" class="group-aria-pressed/toggle:fill-foreground" />
إشارة مرجعية
</twig:Toggle>
{# Hebrew #}
<twig:Toggle variant="outline" size="sm" aria-label="Toggle bookmark" dir="rtl">
<twig:ux:icon name="lucide:bookmark" class="group-aria-pressed/toggle:fill-foreground" />
סימנייה
</twig:Toggle>
</div>
API Reference
Component Toggle
| Prop | Type | Description |
|---|---|---|
variant |
'default'|'outline' |
The visual style variant. Defaults to default |
size |
'default'|'sm'|'lg' |
The toggle size. Defaults to default |
pressed |
boolean |
Whether the toggle is initially pressed. Defaults to false |
| Block | Description |
|---|---|
content |
The toggle label and/or icon |