NakedSwitch

Headless on/off control built on top of NakedToggle with switch semantics for accessibility

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

See the runnable sample in example/lib/api/naked_toggle.0.dart under the "Switch" section.

Basic implementation

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 for the complete property breakdown and grouped option patterns.