npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

css-vars-hook

v0.7.9

Published

css-vars-hook contains React hooks to set and manipulate CSS custom properties from React component.

Downloads

488

Readme

Node.js CI yarn version npm types included npm bundle size

CSS Variables React hook

NPM library Create React App template logo

css-vars-hook contains React hooks to set and manipulate CSS custom properties (variables).

Demo

dev.to article

Highlights

  • CSS Variables in React: manage your component design in a fast and convenient way.
  • Dynamic Theming: create and manage themes for your application. Apply multiple CSS variables to any HTML element.
  • TypeScript Support: The library is written in TypeScript, offering type safety and enhancing developer experience.
  • Zero Dependencies: It operates independently without the need for additional libraries, ensuring a lightweight integration.
  • Performance: The hook is optimized for performance, with a small footprint that does not impact application speed.

Install

npm install css-vars-hook

Usage

css-vars-hook exposes two hooks: useRootTheme, useLocalTheme. Both of them provide developer a bridge between React Component state and CSS Custom Properties.

useRootTheme

useRootTheme applies application level themes. API consists of two elements: the hook itself and RootThemeProvider component which acts as :root selector. Directly applying theme to the :root is not compatible with Server side rendering (SSR).

Manipulate theme

Set up

In order to set global theming you need to wrap your application with RootThemeProvider on highest possible level.

// App.js
import React from 'react';
import {RootThemeProvider} from 'css-vars-hook';

// Theme object contains dictionary of CSS variables you will use later in your application
const theme = {
    boxColor: 'purple',
    borderColor: 'violet',
}

export const App = () => (
    <RootThemeProvider
        theme={theme}>
        {/*...*/}
    </RootThemeProvider>
);

Memoize theme

To avoid unnecessary reconciliations and re-renders theme object has to preserve referential equality during component lifecycle.

Wrong examples

Arbitrary objects are recreated every time React component reconciles. Avoid this when defining theme object.

// Don't do this!!!
const Component: FC = () => {
    //...
    const theme = {
        foo: 'bar'
    }

    return <RootThemeProvider theme={theme}>{/*...*/}</RootThemeProvider>
}
// Don't do this!!!
const Component: FC = () => {
    //...
    return <RootThemeProvider theme={{ foo: 'bar' }}>{/*...*/}</RootThemeProvider>
}

Correct examples

Set theme object externally to Component or wrap with useMemo.

// Correct!
const theme = {
    foo: 'bar'
}

const Component: FC = () => {
    return <RootThemeProvider theme={theme}>{/*...*/}</RootThemeProvider>
}
// Correct! Theme will preserve until foo property change
const Component: FC<{foo: string}> = ({foo}) => {

    const theme = useMemo(() => ({foo}), [foo])

    return <RootThemeProvider theme={theme}>{/*...*/}</RootThemeProvider>
}

Change theme

Theme changing methods (setTheme, setVariable, removeVariable) are implemented as effects. They will apply after component re-render. You'll have to wrap the side effect with useEffect or put in inside callback to move it out of the rendering calculation.

// Component.jsx
import React, { useEffect, useCallback } from "react";
import { useRootTheme } from 'css-vars-hook';

const theme = {
  boxColor: 'red',
  borderColor: 'green',
}

const Component = () => {
  const { setTheme, setVariable, removeVariable } = useRootTheme();

  // Set theme value inside useEffect hook
  useEffect(() => {
    // Theme changing effects can be applied like this. The change will happen after render.
    setTheme(theme);
  }, [theme, setTheme])

  // Set theme value inside callback
  const handleVariable = useCallback(() => {
    setVariable('boxColor', 'pink');
  }, [])

  return <button onClick={handleVariable}>Change variable</button>;
}

Caveats

//...
const Component = () => {
  const { setTheme } = useRootTheme();

  // This will not work!
  setTheme(theme)

  //...
}

The reason this code isn’t correct is that it tries to do something with the DOM node during rendering. In React, rendering should be a pure calculation of JSX and should not contain side effects like modifying the DOM. Moreover, when Component is called for the first time, its DOM does not exist yet, so there is no theme container to operate with.

Type safety

Global theme type should be defined on a project level. You'll have to redeclare ThemeType export from css-vars-hook

// types.d.ts
import theme from '@/theme';

declare module 'css-vars-hook' {
    // Provide your global theme type here
    export type ThemeType = typeof theme;
}

Consume the theme data

CSS variables set by RootThemeProvider are available globally across all application.

In CSS

// Component.css

.box {
    background: var(--boxColor);
    border: 1px solid var(--borderColor)
}

In JS

import {useRootTheme} from 'css-vars-hook';

const {
    /** Get current theme */
    getTheme,
    /** Get variable value within active theme */
    getVariable,
} = useRootTheme();

console.log(getVariable('boxColor')) // => 'purple'
console.log(getTheme()) // => theme object

useLocalTheme

useLocalTheme applies theme locally to the wrapped React components.

Set up a local theme

In order to set local theme you need to wrap your component with LocalRoot component which is returned by useLocalTheme hook.

import { useLocalTheme } from 'css-vars-hook';
import { useCallback } from "react";

const theme = { boxColor: 'yellow' };
const darkTheme = {boxColor: 'darkYellow'};

const Component = () => {
  const { LocalRoot, setTheme } = useLocalTheme();
  const setDarkMode = useCallback(() => {
    setTheme(darkTheme)
  }, []);
  return <LocalRoot theme={theme}>{/*...*/}</LocalRoot>
}

Outside different wrapping strategies this hook is similar to useRootTheme.

Customize LocalRoot element

By default LocalRoot is rendered as a div HTMLElement. You can provide custom element type (button, span, e. t. c.) by changing as prop of LocalRoot.

import {useLocalTheme} from 'css-vars-hook';

const theme = {boxColor: 'yellow'};
const darkTheme = {boxColor: 'darkYellow'};

const Component = () => {
    const {LocalRoot: Button, setTheme} = useLocalTheme();
    const setDarkMode = useCallback(() => {
      setTheme(darkTheme)
    }, [])
    return (
      <Button
        theme={theme}
        as="button"
        onClick={setDarkMode}>
        Set dark mode
      </Button>
    )
}

Type safety

Local theme type is inferred from corresponding LocalRoot prop.