Skip to content

MultiThemeToggle

Bryce Russell edited this page Jan 16, 2023 · 7 revisions

An advanced multi theme toggle button / theme management script

The easiest way to use this component is in a component that is shared across all pages like a layout, navbar, footer, etc

Note: If your website only needs a light(default) and dark theme then try out the much smaller and simpler <DarkThemeToggle> component

Features

  • Define what element gets themed
  • Use multiple <MultiThemeToggle> together
  • Scoped, theme more than one element on a page
  • Persistent using sessionStorage
  • Option to add system preference listener
  • Ability to hide button and keep script for persistence
  • Automatically add and aria-label, can override

When do I use this?

This component is used when you want more than two themes (light/dark), it allows you to define as many theme options (classes) for an element as you want and even have multiple themed elements per page with persistence and system preference detection

How to use

---
import { MultiThemeToggle } from 'astro-headless-ui';
---

<MultiThemeToggle>Toggle Dark Theme</MultiThemeToggle>
<MultiThemeToggle theme="green">Toggle Green Theme</MultiThemeToggle>
<MultiThemeToggle theme="blue">Toggle Blue Theme</MultiThemeToggle>

Output:

<script> ... </script>
<button onclick="darkTogglergnSG()" aria-label="Toggle dark theme">
  Toggle Dark Theme
</button>

<script> ... </script>
<button onclick="greenTogglergnSG()" aria-label="Toggle green theme">
  Toggle Green Theme
</button>

<script> ... </script>
<button onclick="blueTogglergnSG()" aria-label="Toggle blue theme">
  Toggle Blue Theme
</button>

Props

selector?: string

Default: body

A document.querySelector() string used to select what element the theme is added to, if undefined script defaults to document.body

scope?: string

Default: hashId(selector)

Only used in advanced cases, recommended to use default

This prop is used to group themes together, all <MultiThemeToggle>s that share the same selector must also share the same scope. This value is used to create sessionStorage keys and declare toggle functions, only suggested to change if you want control over key/function names

theme?: string

Default: dark

The name of the theme, added as a class to selector, this should be a one word lowercase string without any special characters

dark?: boolean

Default: false

If true, attaches theme to event listener for system theme preference changes. Adds theme as class if dark mode is true, removes all theme classes from the selector if dark mode is false (light mode). Can only be used on one <MultiThemeToggle> per selector

hide?: boolean

Default: false

Stops the button from rendering, but keeps the script. Useful for pages where the dark theme should persist without a toggle button on the page

...attrs

Type: HTMLAttributes<'button'>

Default:

{
  onclick: `${theme}Toggle${scope}()`,
  'aria-label': `Toggle ${theme} theme`,
}

All other props passed to this component are passed as attributes to the toggle button (id, class, style, aria-label, ...)

Examples

Persist themes without button

Add this to pages where the theme should persist without any visible toggle buttons

<MultiThemeToggle hide />

Listen to system theme preference changes

Use the dark prop on a theme to for it to detect dark theme preference, can only be used on one <MultiThemeToggle> per selector

<MultiThemeToggle dark>This theme will toggle if prefers-color-scheme is dark</MultiThemeToggle>
<MultiThemeToggle theme="blue">This theme will only toggle if this button is clicked</MultiThemeToggle>

Scope themes using selector

Themes can be added to any element on the page using the selector prop, this example adds 4 theme options to only the footer

<MultiThemeToggle selector="footer">Toggle Dark Footer Theme</MultiThemeToggle>
<MultiThemeToggle selector="footer" theme="blue" dark>Toggle Blue Footer Theme</MultiThemeToggle>
<MultiThemeToggle selector="footer" theme="green">Toggle Green Footer Theme</MultiThemeToggle>
<MultiThemeToggle selector="footer" theme="red">Toggle Red Footer Theme</MultiThemeToggle>

Using with <IconSwitcher>

---
import { MultiThemeToggle, IconSwitcher } from 'astro-headless-ui';
import { Icon } from 'astro-icon';
---
<MultiThemeToggle style="padding:.5rem;">
  <IconSwitcher size="2rem"> 
    <Icon name="ri:sun-foggy-line"/>
    <Icon name="ri:moon-cloudy-line"/>
  </IconSwitcher>
</MultiThemeToggle>