Skip to content

Toggle

Basic Usage

The Toggle field renders a switch-style toggle. By default, it stores true when on and false when off.

Example
php
Toggle::make('notifications')
    ->label('Email notifications')
    ->default(true);

Use Toggle for a single on/off value. For multiple related choices, use CheckboxGroup; for one-of-many choices, use Radio.

Custom Values

Customize what gets stored when the toggle is on or off:

php
Toggle::make('status')
    ->onValue('active')
    ->offValue('inactive');

Toggle::make('is_public')
    ->onValue(1)
    ->offValue(0);

Supported cross-stack values are strings, numbers, booleans, and null. PHP preserves a model or default value that strictly matches either configured value. Any other value is converted using PHP truthiness, then mapped to onValue or offValue. Vue and React also use strict value equality to decide whether the switch is on.

For example, this field writes null when it is off:

php
Toggle::make('status')
    ->onValue('enabled')
    ->offValue(null);

Validation

Toggle does not add a boolean or acceptance rule automatically. Add the Laravel rule that matches the configured values. required() only adds Laravel's required rule and exposes aria-required; it does not mean the switch must be on. Use accepted for an on/off value that must be enabled.

Labels

Add text labels that appear next to the toggle. Labels pair well with custom stored values when the submitted value is not a boolean:

Example
PrivatePublic
php
Toggle::make('visibility')
    ->label('Portal visibility')
    ->onValue('public')
    ->offValue('private')
    ->onLabel('Public')
    ->offLabel('Private')
    ->color('#16a34a')
    ->default('public');

onLabel() and offLabel() are optional visible state labels. They do not change the accessible name of the switch, which comes from the field label or an explicitly forwarded aria-label.

Icons

You may add icons inside the toggle thumb by passing resolver-backed icon names. See Icons:

Example
php
Toggle::make('dark_mode')
    ->onIcon('MoonIcon')
    ->offIcon('SunIcon');

The icon resolver receives the configured name only for the active state. Icons are decorative and do not replace the field label.

Size

Three sizes are available: sm, md (default), and lg.

Example
php
Toggle::make('small_toggle')->label('Small')->sm();
Toggle::make('medium_toggle')->label('Medium')->md();
Toggle::make('large_toggle')->label('Large')->lg();

Or use the generic method:

php
Toggle::make('notifications')->size('lg');

Vue and React fall back to the medium styles for any unrecognized serialized size. Use sm(), md(), or lg() for the supported public contract.

Color

Customize the active color of the toggle with any valid CSS color value:

php
Toggle::make('notifications')->color('#16a34a');
Toggle::make('maintenance_mode')->color('rgb(220 38 38)');

The custom color applies only to the on-state track. Passing null restores the theme accent color.

Loading

Show a loading spinner while an update is pending. A loading toggle is busy and disabled, so user interaction may not change it until loading ends:

Example
php
Toggle::make('syncing')->loading();
Toggle::make('locked_setting')->disabled();

Using the Component Directly

You may render Toggle with local state, or pass serialized field props during manual form rendering.

vue
<script setup lang="ts">
import { Toggle } from '@inertiaui/form-vue/components'
import { Moon, Sun } from '@lucide/vue'
import { ref } from 'vue'
import type { IconResolverFn } from '@inertiaui/form-vue'

const theme = ref<'dark' | 'light'>('light')
const saving = ref(false)
const canEdit = ref(true)

const icons = { MoonIcon: Moon, SunIcon: Sun }
const iconResolver: IconResolverFn = (icon) => icons[icon as keyof typeof icons] ?? null

const toggleParts = {
  track: 'ring-1 ring-zinc-950/10',
  thumb: 'ring-1 ring-zinc-950/10',
}

const trackBlur = () => {}
</script>

<template>
  <Toggle
    v-model="theme"
    id="theme-mode"
    name="theme_mode"
    label="Theme mode"
    help="Applied to the current workspace."
    on-value="dark"
    off-value="light"
    on-label="Dark"
    off-label="Light"
    on-icon="MoonIcon"
    off-icon="SunIcon"
    size="lg"
    color="#16a34a"
    :loading="saving"
    :disabled="!canEdit"
    :icon-resolver="iconResolver"
    required
    precognitive
    invalid
    error="Choose an available theme mode."
    badge="Workspace"
    badge-class="bg-zinc-100 text-zinc-700"
    label-trailing="Required"
    label-trailing-class="text-zinc-500"
    tooltip="Shown to every member of this workspace."
    help-position="below"
    layout="stacked"
    control-position="end"
    label-class="font-medium"
    help-class="text-zinc-500"
    error-class="text-red-600"
    wrapper-class="max-w-xl"
    control-class="bg-white"
    class="font-medium"
    :part-classes="toggleParts"
    data-testid="theme-toggle"
    aria-label="Theme mode"
    @blur="trackBlur"
  />
</template>
tsx
import { useState } from 'react'
import { MoonIcon, SunIcon } from 'lucide-react'
import { Toggle } from '@inertiaui/form-react/components'
import type { IconResolverFn } from '@inertiaui/form-react'

const icons = { MoonIcon, SunIcon }
const iconResolver: IconResolverFn = (icon) => icons[icon as keyof typeof icons] ?? null

const toggleParts = {
    track: 'ring-1 ring-zinc-950/10',
    thumb: 'ring-1 ring-zinc-950/10',
}

export default function ThemeToggle() {
    const [theme, setTheme] = useState<'dark' | 'light'>('light')
    const [saving] = useState(false)
    const [canEdit] = useState(true)
    const trackBlur = () => {}

    return (
        <Toggle
            value={theme}
            onValueChange={(value) => setTheme(value as 'dark' | 'light')}
            id="theme-mode"
            name="theme_mode"
            label="Theme mode"
            help="Applied to the current workspace."
            onValue="dark"
            offValue="light"
            onLabel="Dark"
            offLabel="Light"
            onIcon="MoonIcon"
            offIcon="SunIcon"
            size="lg"
            color="#16a34a"
            loading={saving}
            disabled={!canEdit}
            iconResolver={iconResolver}
            required
            precognitive
            invalid
            error="Choose an available theme mode."
            badge="Workspace"
            badgeClass="bg-zinc-100 text-zinc-700"
            labelTrailing="Required"
            labelTrailingClass="text-zinc-500"
            tooltip="Shown to every member of this workspace."
            helpPosition="below"
            layout="stacked"
            controlPosition="end"
            labelClass="font-medium"
            helpClass="text-zinc-500"
            errorClass="text-red-600"
            wrapperClass="max-w-xl"
            controlClass="bg-white"
            class="font-medium"
            partClasses={toggleParts}
            data-testid="theme-toggle"
            aria-label="Theme mode"
            onBlur={trackBlur}
        />
    )
}

Vue uses v-model. React uses controlled value plus onValueChange. Native attributes and listeners target the underlying button; see Native Attributes and Events.

All shared field methods remain available. See Validation, Conditional Visibility, Authorization, Model Binding, Form Class, Icons, and Styling for rules, visibility, authorization, model values, runtime configuration, icon resolvers, labels, help, layout, and classes.