Documentation
Dark Mode

Dark Mode

There are 2 ways to customize styles for dark mode in Morfeo, one at Style level, similar to how Morfeo's handles Responsive Styles, and one at Theme level.

Style Level

Just like with the Responsive Value, we can pass to properties an object that specifies the value that the property should have for dark (or light) mode:

components/Card
import { morfeo } from '../morfeo';
 
const classes = morfeo.css({
  container: {
    px: 'm',
    bg: {
      light: 'black',
      dark: 'white',
    },
    color: {
      light: 'white',
      dark: 'black',
    },
  },
});
 
export function Card() {
  return (
    <div className={classes('container')}>
      This card will have a different background and text color based on the
      user's preferred scheme.
    </div>
  );
}

Theme Level

In most of the applications, the difference between dark and light modes is just colors and something color-related like gradients and shadows.

Morfeo makes you customize exactly these slices so then it will apply the right styles at the right color schemes automatically, so you don't have to worry about it while styling your components:

The values of the colors background and text, when used inside a style, will automatically be adapted based on the current user's preferred color scheme.

morfeo.ts
const theme = {
  // ...
  colors: {
    primary: '#0066ff', // Always the same no matter the color scheme.
    // Dynamic color
    background: {
      light: '#ffffff', // Used only in light mode
      dark: '#000000', // Used only in dark mode
    },
    // Dynamic color
    text: {
      light: '#2f2f2f', // Used only in light mode
      dark: '#ececec', // Used only in dark mode
    },
  },
};

Customization

Sometimes you want to switch between a light and dark mode in other ways than the @media (prefers-colors-scheme) rule, Morfeo lets you customize this completely by overriding the slice colorSchemes, for example:

const theme = {
  // ...
  colorSchemes: {
-    dark: '@media (prefers-color-scheme: 'dark')',
+    dark: '[data-theme="dark"]',
-    light: '@media (prefers-color-scheme: 'light')',
+    light: '[data-theme="light"]',
    /**
     * No one is blocking you from creating custom color schemes too, but be aware that the only
     * possible values for "@media (prefers-colors-scheme)" are light and dark.
     */
    custom: '[data-theme="custom"]',
  },
};

With this customization, you're telling Morfeo to use dark-specific values under any HTML element that has the data-theme attribute equal to dark:

components/Card
import { morfeo } from '../morfeo';
 
const classes = morfeo.css({
  button: {
    bg: {
      light: 'primary',
      dark: 'secondary',
    },
  },
});
 
export function Card() {
  const [darkMode, setDarkMode] = useState(false);
 
  function toggleDarkMode() {
    setSchema(prev => !prev);
  }
 
  return (
    <div data-theme={darkMode ? 'dark' : 'light'}>
      The following button will have the background color equal to "primary" if
      in light mode, "secondary" otherwise.
      <button className={classes('button')} onClick={toggleDarkMode}>
        Toggle
      </button>
      <div data-theme="light">
        Here instead, the button will always have a "primary" background because
        light mode is forced.
        <button className={classes('button')} onClick={toggleDarkMode}>
          Toggle
        </button>
      </div>
    </div>
  );
}