Honeycomb

use-theme-switcher

Deprecated

since 16.0.0. The `user-preference` functionality choosing dark theme is now available on the `ThemeWrapper` component. It is also now very easy to toggle `dark` mode. This hook is now not needed as you can achieve the same result easier with just the ThemeWrapper. A hook that handles detecting user color scheme preference to switch between light and dark theme names.

Since: ver.10.0.0

Props

Prop nameTypeDefaultDescription
lightThemeThemeNameRequired

The name of the theme to be used on light mode.

darkThemeThemeNameRequired

The name of the theme to be used on dark mode.

switchConditionboolean | undefined

Custom condition to run for matching darkTheme preference.

The useThemeSwitcher hook abstracts logic to switch between two themes and also detect the user preferred color scheme to automatically pick the adequate theme name.

The hook returns an array with:

`theme`
Current theme name.
`toggleTheme`
A function to toggle between two themes.
`setTheme`
The function to directly set the theme.

Basic theme switching using toggleTheme

The most basic setup only takes two arguments: lightTheme and darkTheme.

Tip: You can emulate the browser color scheme preference on the DevTools "Rendering" tool.

import { Box, Button, Text, ThemeWrapper, themeFlix, themeKamil, useThemeSwitcher } from '@flixbus/honeycomb-react';

const [theme, toggleTheme] = useThemeSwitcher({
  lightTheme: 'flix',
  darkTheme: 'kamil'
});

const isKamil = theme === 'kamil';

<ThemeWrapper theme={theme} themes={[themeFlix, themeKamil]}>
  <Box>
    <Text>
      I prefer "{isKamil ? 'Kamil' : 'Flix'}" theme
    </Text>
    <Button onClick={() => toggleTheme()} appearance="primary">
      {`Go back to ${isKamil ? 'Flix' : 'Kamil'}`}
    </Button>
  </Box>
</ThemeWrapper>

Using the setTheme function

If you need to set a theme name directly, you can use the setTheme function. This will bypass the hook's internal logic.

In the example bellow the buttons simply set one of the themes, while the hook only runs at the first render.

import { Box, Button, ButtonGroup, Text, ThemeWrapper, themeFlix, themeKamil, useThemeSwitcher } from '@flixbus/honeycomb-react';
import { Icon, IconFlix, IconFlixNo } from '@flixbus/honeycomb-icons-react';

const [theme, , setTheme] = useThemeSwitcher({
  lightTheme: 'flix',
  darkTheme: 'kamil'
});

<ThemeWrapper theme={theme} themes={[themeFlix, themeKamil]}>
  <Box>
    <Text>
      I'm using "{theme}" theme.
    </Text>
    <ButtonGroup>
      <Button appearance="primary" onClick={() => setTheme('flix')}>
        <Icon InlineIcon={IconFlix} /> Go Flix!
      </Button>
      <Button appearance="primary" onClick={() => setTheme('kamil')}>
        <Icon InlineIcon={IconFlixNo} /> Go Kamil!
      </Button>
    </ButtonGroup>
  </Box>
</ThemeWrapper>

Setting a custom user preference condition with switchCondition option

By default the hook will detect if the user prefers dark color scheme by matching the media query: (prefers-color-scheme: dark).

You can override this behavior by passing a boolean resulting condition to the switchCondition option.

In the example bellow we write a custom condition to check the time and assess if it's morning or night, then choose dark theme if it's night. Set the time using the input to change the theme on the fly.

Another example of custom switchCondition is wether the user has a saved theme preference on their profile or cookies.

import { Box, FormRow, Input, ButtonGroup, Button, ThemeWrapper, themeFlix, themeKamil, useThemeSwitcher } from '@flixbus/honeycomb-react';
import { Icon, IconBulb, IconBulbOff } from '@flixbus/honeycomb-icons-react';

const [time, setTime] = React.useState(`${new Date().getHours().toString()}:00`);
const hours = time.split(':')[0];
const isNight = hours >= 18 || hours < 6;

const [theme] = useThemeSwitcher({
  lightTheme: 'flix',
  darkTheme: 'kamil',
  switchCondition: isNight
});

const info = (<>
  Now is {isNight ? 'night' : 'day'}
  <Icon InlineIcon={isNight ? IconBulb : IconBulbOff} />
</>);

<ThemeWrapper theme={theme} themes={[themeFlix, themeKamil]}>
  <Box>
    <FormRow>
      <Input type="time" label="Set the time" info={info} id="timed-theme-switcher" value={time} step="3600" onChange={(event) => setTime(event.target.value)} />
    </FormRow>
    <ButtonGroup>
      <Button appearance="primary">
        Primary button
      </Button>
    </ButtonGroup>
  </Box>
</ThemeWrapper>