ArcaneThemeToggle
Toggle button for switching between light and dark themes
Live Demo
🌙

ArcaneThemeToggle#

A specialized toggle component for switching between light and dark theme modes.

Basic Usage#

ArcaneThemeToggle(
  isDark: isDarkMode,
  onToggle: (isDark) {
    setState(() => isDarkMode = isDark);
  },
)

Properties#

PropertyTypeDefaultDescription
isDark bool false Current theme mode
onToggle ValueChanged<bool>? null Mode change handler
size ThemeToggleSize medium Toggle size
showLabel bool false Show text label
styles ArcaneStyleData? null Custom styling

Simple Version#

For a simpler toggle that syncs with system theme:

ArcaneThemeToggleSimple()

Sizes#

// Small
ArcaneThemeToggle(
  isDark: isDark,
  size: ThemeToggleSize.small,
  onToggle: (v) => setState(() => isDark = v),
)

// Medium (default)
ArcaneThemeToggle(
  isDark: isDark,
  size: ThemeToggleSize.medium,
  onToggle: (v) => setState(() => isDark = v),
)

// Large
ArcaneThemeToggle(
  isDark: isDark,
  size: ThemeToggleSize.large,
  onToggle: (v) => setState(() => isDark = v),
)

With Label#

ArcaneThemeToggle(
  isDark: isDarkMode,
  showLabel: true,
  onToggle: (v) => setState(() => isDarkMode = v),
)

Examples#

Header with Theme Toggle#

ArcaneBar(
  leading: [
    ArcaneText('Logo'),
  ],
  trailing: [
    ArcaneButton.ghost(label: 'Docs', onPressed: () {}),
    ArcaneButton.ghost(label: 'Pricing', onPressed: () {}),
    ArcaneThemeToggle(
      isDark: isDarkMode,
      onToggle: (isDark) {
        setState(() => isDarkMode = isDark);
        updateTheme(isDark);
      },
    ),
  ],
)

Settings Page#

ArcaneDiv(
  styles: const ArcaneStyleData(
    display: Display.flex,
    justifyContent: JustifyContent.spaceBetween,
    alignItems: AlignItems.center,
    padding: PaddingPreset.md,
    background: Background.surface,
    borderRadius: Radius.lg,
  ),
  children: [
    ArcaneDiv(
      children: [
        ArcaneText('Theme'),
        ArcaneDiv(
          styles: const ArcaneStyleData(
            fontSize: FontSize.sm,
            textColor: TextColor.muted,
          ),
          children: [ArcaneText('Switch between light and dark mode')],
        ),
      ],
    ),
    ArcaneThemeToggle(
      isDark: isDarkMode,
      onToggle: (isDark) {
        setState(() => isDarkMode = isDark);
        savePreference('theme', isDark ? 'dark' : 'light');
      },
    ),
  ],
)
ArcaneDropdownMenu(
  children: [
    ArcaneDropdownItem(
      label: 'Profile',
      onPressed: () => goToProfile(),
    ),
    ArcaneDropdownItem(
      label: 'Settings',
      onPressed: () => goToSettings(),
    ),
    ArcaneDivider(),
    ArcaneDiv(
      styles: const ArcaneStyleData(
        display: Display.flex,
        justifyContent: JustifyContent.spaceBetween,
        alignItems: AlignItems.center,
        padding: PaddingPreset.smMd,
      ),
      children: [
        ArcaneText('Dark mode'),
        ArcaneThemeToggle(
          isDark: isDarkMode,
          size: ThemeToggleSize.small,
          onToggle: (v) => toggleTheme(v),
        ),
      ],
    ),
    ArcaneDivider(),
    ArcaneDropdownItem(
      label: 'Sign out',
      onPressed: () => signOut(),
    ),
  ],
)
ArcaneFooter(
  children: [
    ArcaneDiv(
      styles: const ArcaneStyleData(
        display: Display.flex,
        justifyContent: JustifyContent.spaceBetween,
        alignItems: AlignItems.center,
      ),
      children: [
        ArcaneText('© 2024 Company'),
        ArcaneDiv(
          styles: const ArcaneStyleData(
            display: Display.flex,
            alignItems: AlignItems.center,
            gap: Gap.sm,
          ),
          children: [
            ArcaneText('Theme:'),
            ArcaneThemeToggle(
              isDark: isDarkMode,
              size: ThemeToggleSize.small,
              onToggle: toggleTheme,
            ),
          ],
        ),
      ],
    ),
  ],
)

Persisting Theme Preference#

class ThemeProvider extends StatefulComponent {
  bool _isDark = false;

  @override
  void initState() {
    super.initState();
    _loadTheme();
  }

  void _loadTheme() async {
    final saved = await storage.get('theme');
    setState(() => _isDark = saved == 'dark');
  }

  void _toggleTheme(bool isDark) async {
    setState(() => _isDark = isDark);
    await storage.set('theme', isDark ? 'dark' : 'light');
  }

  @override
  Iterable<Component> build(BuildContext context) sync* {
    yield ArcaneApp(
      theme: ArcaneTheme.supabase(
        themeMode: _isDark ? ThemeMode.dark : ThemeMode.light,
      ),
      child: YourApp(
        themeToggle: ArcaneThemeToggle(
          isDark: _isDark,
          onToggle: _toggleTheme,
        ),
      ),
    );
  }
}