---
title: NakedSwitch
description: Headless on/off control built on top of NakedToggle with switch semantics for accessibility
keywords: [flutter, switch, toggle, settings, accessibility, headless]
---

Headless switch component. Handles toggle behavior and accessibility with switch semantics. Use builder pattern for custom styling.

## When to use this

- **Settings controls**: Enable/disable features (notifications, dark mode)
- **Preferences**: Binary choices in configuration panels
- **Feature toggles**: Turn functionality on or off
- **Status controls**: Active/inactive, enabled/disabled states

<Info>
  See the runnable sample in [`packages/example/lib/api/naked_toggle.0.dart`](https://github.com/btwld/naked_ui/blob/main/packages/example/lib/api/naked_toggle.0.dart) under the "Switch" section.
</Info>

## Basic implementation

```dart
import 'package:flutter/material.dart';
import 'package:naked_ui/naked_ui.dart';

class SettingsSwitch extends StatefulWidget {
  const SettingsSwitch({super.key});

  @override
  State<SettingsSwitch> createState() => _SettingsSwitchState();
}

class _SettingsSwitchState extends State<SettingsSwitch> {
  bool _notificationsEnabled = true;

  @override
  Widget build(BuildContext context) {
    return NakedToggle(
      value: _notificationsEnabled,
      asSwitch: true,
      semanticLabel: 'Email notifications',
      onChanged: (next) => setState(() => _notificationsEnabled = next),
      builder: (context, state, _) {
        final bool isToggled = state.isToggled;
        final bool isDisabled = state.isDisabled;

        final backgroundColor = state.when(
          disabled: Colors.grey.shade300,
          toggled: Colors.green.shade500,
          orElse: Colors.grey.shade400,
        );

        return AnimatedContainer(
          duration: const Duration(milliseconds: 180),
          width: 48,
          height: 28,
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(14),
            color: backgroundColor,
          ),
          child: AnimatedAlign(
            duration: const Duration(milliseconds: 180),
            alignment: isToggled ? Alignment.centerRight : Alignment.centerLeft,
            child: Container(
              margin: const EdgeInsets.all(2),
              width: 24,
              height: 24,
              decoration: BoxDecoration(
                color: Colors.white,
                shape: BoxShape.circle,
                boxShadow: [
                  BoxShadow(
                    color: Colors.black.withOpacity(0.1),
                    blurRadius: 3,
                    offset: const Offset(0, 1),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );
  }
}
```

## Shared API

All constructor parameters and callbacks are identical to `NakedToggle`. The important pieces when shipping a switch experience are:

- Keep `asSwitch: true`
- Supply a descriptive `semanticLabel`
- Use the typed `NakedToggleState` in the builder to style hover, focus, and pressed affordances
- Disable the control by omitting `onChanged`

Refer to the [NakedToggle documentation](./toggle) for the complete property breakdown and grouped option patterns.
