Skip to content

Instantly share code, notes, and snippets.

@pedrowindisch
Last active May 26, 2021 19:42
Show Gist options
  • Save pedrowindisch/3ecf37f0af67ac08d464f8f612256027 to your computer and use it in GitHub Desktop.
Save pedrowindisch/3ecf37f0af67ac08d464f8f612256027 to your computer and use it in GitHub Desktop.
useTheming - react hooks

useTheming

simple react hooks that makes theming your app easier and straightforward.

copy useTheming.js and paste it on your project folder, then initialize it.

import React from 'react';
import useTheming from './hooks/useTheming';

const App = () => {
  // You can just straightforward call the useTheming hooks like below.
  useTheming();
  
  return (
    //...
  );
};

return App;

How to get the current theme?

The useTheming() functions has two return values:

  • theme - {'light'|'dark'} your current theme.
  • handleThemeChange() - a function to change the current theme. Rename it as you wish.

So, if you want to get the current theme of your app, you can just call the hooks and use its first return value.

const App = () => {
  const [theme] = useTheming();
  
  return (
    <h1>{theme}</h1>
  );
};

How to change the current theme?

const App = () => {
  const [theme, changeTheme] = useTheming();
  
  const handleOnClick = () => {
    const newTheme = theme === 'dark' ? 'light' : 'dark';
    
    changeTheme(newTheme);
  };
  
  return (
    <React.Fragment>
      <h1>{theme}</h1>
      <button onClick={handleOnClick}>
        Change theme
      </button>
    </React.Fragment>
  );
};

How about the theming itself? How do I make my app look different if the theme is dark and vice-versa?

You have to create CSS variables. The dark theme will be wrapped inside a [data-theme="dark"] block, like this:

:root {
  --title-color: #000;
}

[data-theme="dark"] {
  --title-color: #FFF;
}

Above, if the current theme is light, the --title-color variable gonna have a value of #000. If the theme is set to dark, the variable will have a value of #FFF.

/**
* @file A hooks to customize the app theming.
*/
import { useState, useEffect, useCallback } from 'react';
/**
* @typedef {'light'|'dark'} ThemeValues
*/
/**
* A hooks to customize the app theming.
* The app theme is customized using CSS variables inside a [data-theme='dark']
* block, e.g.:
*
* ```css
* :root {
* --shadow-color: blue;
* }
*
* [data-theme="dark"] {
* --shadow-color: red;
* }
* ```
*
* You can change the theme by calling the setTheme function with
* one of the possible values - 'light' or 'dark'.
*
* @returns {[ThemeValues, handleThemeChange]} - The current color scheme and a function to
* to update it.
*/
const useTheming = () => {
const [theme, setTheme] = useState('light');
/**
* Checks if the system already supports the
* prefers-color-scheme media query. If so, returns
* the query itself.
* Returns 'light' otherwise.
*
* @returns {(ThemeValues)} - The system theme.
*/
const getSystemTheme = () => {
// If the browser doesn't support CSS media queries,
// returns 'light'.
if (!window.matchMedia) return 'light';
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
return 'dark';
}
return 'light';
};
/**
* Checks if a theme is saved on the local storage.
* If no theme is set, fallbacks to the system theme.
*
* @returns {(ThemeValues)}
*/
const getLocalStorageTheme = useCallback(() => {
const localStorageTheme = localStorage.getItem('theme');
if (localStorageTheme) return localStorageTheme;
// If no theme is stored, use the system one.
return getSystemTheme();
}, []);
/**
* @param {ThemeValues} newTheme
*/
const setLocalStorageTheme = (newTheme) => {
localStorage.setItem('theme', newTheme);
};
/**
* Updates the app theme and the document attributes.
*
* @param {ThemeValues} newTheme
*/
const handleThemeChange = useCallback((newTheme) => {
// Sets the document data-theme attribute.
// The data-theme attribute changes the CSS variables.
document.documentElement.setAttribute('data-theme', newTheme);
setLocalStorageTheme(newTheme);
setTheme(newTheme);
}, []);
useEffect(() => {
const predefinedTheme = getLocalStorageTheme();
handleThemeChange(predefinedTheme);
}, [getLocalStorageTheme, handleThemeChange]);
return [theme, handleThemeChange];
};
export default useTheming;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment