This library requires a React Canary version since it utilizes the new style hoisting feature.

restyle logo

Zero Config
CSS for React

The simplest way to add CSS to React.
No build configuration required.

npm install restyle

Input

import { styled } from "restyle";

const Button = styled("button", {
  padding: "0.5rem 1rem",
  borderRadius: "4px",
  backgroundColor: "blue",
  color: "white",
});

export default function Page() {
  return (
    <Button
      css={{
        paddingInline: "0.8rem",
        backgroundColor: "pink",
      }}
      onClick={() => alert()}
    >
      Click me!
    </Button>
  );
}

Output

<html>
  <head>
    <style data-precedence="rsl" data-href="xwci5pk">
      .x6vw34k {
        padding: 0.5rem 1rem;
      }
      .x1xg4490 {
        border-radius: 4px;
      }
    </style>
    <style data-precedence="rsm" data-href="x1pc7fh0">
      .x1f9e8ue {
        padding-inline: 0.8rem;
      }
    </style>
    <style data-precedence="rsh" data-href="xbg6jus">
      .x1yju78o {
        background-color: pink;
      }
      .xpzun7g {
        color: white;
      }
    </style>
  </head>
  <body>
    <button class="x6vw34k x1xg4490 x1yju78o xpzun7g x1f9e8ue">
      Click me!
    </button>
  </body>
</html>

Features

Atomic class names

Optimized for minimal CSS generation.

Style props

Control styles using props.

Suspense friendly

Works with Suspense and streaming.

Isomorphic styling

Compatible with server and client rendering.

Encourages encapsulation

Keep styles colocated and maintainable.

Supports css prop

Apply styles directly to your JSX elements.

Loads styles on demand

Only injects styles when they are used.

Ship CSS in NPM packages

Distribute styles with your NPM packages.

2.1kb minified & gzipped

Tiny core size for optimal performance.

Examples

Styled Function

The styled function is a higher-order function that takes an HTML element tag name or a component that accepts a className prop and a initial styles object that returns a styled component that can accept a css prop:

import Link from "next/link";
import { styled } from "restyle";

const StyledLink = styled(Link, {
  color: "rebeccapurple",
  textDecoration: "none",
});

Style Props

The second argument to the styled function also accepts a function that returns a styles object based on the props passed to the component:

import { styled } from "restyle";

type GridProps = {
  gridTemplateColumns: string;
};

const Grid = styled("div", (props: GridProps) => ({
  display: "grid",
  gridTemplateColumns: props.gridTemplateColumns,
}));

Now you can use these props to style the component:

<Grid gridTemplateColumns="repeat(3, 1fr)">
  <div>1</div>
  <div>2</div>
  <div>3</div>
</Grid>;

Note, a proxy is used to differentiate between style props and those passed directly to the component. Therefore, only style props should be accessed within the function to ensure proper filtering.

CSS Function

The css function returns a tuple of class names and the style tags to render. You can use the class names to apply styles to an element and the style tag to inject the styles into the head of the document:

import React from "react";
import { css } from "restyle";

export default function BasicUsage() {
  const [classNames, Styles] = css({
    padding: "1rem",
    backgroundColor: "peachpuff",
  });

  return (
    <>
      <div className={classNames}>Hello World</div>
      <Styles />
    </>
  );
}

CSS Prop

The css function is most useful for components. However, you can use the css prop to style elements directly. The pragma will take care of applying the class names and injecting the style tag.

First, configure the pragma in your tsconfig.json file:

{
  "compilerOptions": {
    "jsxImportSource": "restyle"
  }
}

Now, you can use the css prop to style elements:

export default function CSSProp() {
  return (
    <div
      css={{
        padding: "1rem",
        backgroundColor: "peachpuff",
      }}
    >
      Hello World
    </div>
  );
}

Alternatively, you can set the pragma at the top of the file:

/** @jsxImportSource restyle */

export default function CSSProp() {
  return (
    <div
      css={{
        padding: "1rem",
        backgroundColor: "peachpuff",
      }}
    >
      Hello World
    </div>
  );
}

Box Component

import React from "react";
import { css } from "restyle";

export function Box({
  children,
  display = "flex",
  alignItems,
  justifyContent,
  padding,
  backgroundColor,
}) {
  const [classNames, Styles] = css({
    display,
    alignItems,
    justifyContent,
    padding,
    backgroundColor,
  });
  return (
    <div className={classNames}>
      {children}
      <Styles />
    </div>
  );
}

Variants

Variants can be achieved by using the style props pattern. For example, you can create an Alert component that accepts a variant prop that applies different styles based on the variant:

import { styled, type CSSObject } from "restyle";

type AlertVariant = "note" | "success" | "warning";

const variantStyles = {
  note: {
    backgroundColor: "#1b487d",
    borderLeftColor: "#82aaff",
  },
  success: {
    backgroundColor: "#2b7b3d",
    borderLeftColor: "#5bc873",
  },
  warning: {
    backgroundColor: "#b36b00",
    borderLeftColor: "#ffb830",
  },
} satisfies Record<AlertVariant, CSSObject>;

export const Alert = styled("div", (props: { variant: AlertVariant }) => {
  return {
    padding: "1.5rem 2rem",
    borderRadius: "0.5rem",
    color: "white",
    ...variantStyles[props.variant],
  };
});

Pseudo Selectors

/** @jsxImportSource restyle */

export default function Hover() {
  return (
    <div
      css={{
        ":hover": {
          opacity: 0.8,
        },
      }}
    >
      Hover me
    </div>
  );
}

Child Selectors

/** @jsxImportSource restyle */

export default function ChildSelectors() {
  return (
    <div
      css={{
        color: "black",
        "> a": {
          color: "tomato",
        },
      }}
    >
      Parent
      <a href="#">Link</a>
    </div>
  );
}

Media Queries

/** @jsxImportSource restyle */

export default function MediaQueries() {
  return (
    <h1
      css={{
        fontSize: "2rem",
        "@media screen and (min-width: 40em)": {
          fontSize: "3.5rem",
        },
      }}
    >
      Resize the window
    </h1>
  );
}

An additional media utility is available to help with creating typed media query keys from objects:

/** @jsxImportSource restyle */
import { media } from "restyle";

export default function MediaQueries() {
  return (
    <h1
      css={{
        fontSize: "2rem",
        [media({ screen: true, minWidth: "40em" })]: {
          fontSize: "3.5rem",
        },
      }}
    >
      Resize the window
    </h1>
  );
}

Keyframes

Use the keyframes utility to easily create CSS animations:

import { keyframes, styled } from "restyle";

const FadeInKeyframes = keyframes({
  from: { opacity: 0 },
  to: { opacity: 1 },
});

const FadeIn = styled("div", {
  animation: `${FadeInKeyframes} 1s ease-in-out`,
});

export default function FadeInComponent() {
  return (
    <>
      <FadeInKeyframes />
      <FadeIn>Hello World</FadeIn>
    </>
  );
}

Global Styles

Use the GlobalStyles component to inject global styles into the document. This is useful for setting default styles for the body, headings, etc. This component accepts an object of styles and injects them into the head of the document based on their order in the object as well as when they are rendered in the react tree. Note, global styles will not be removed when the component is unmounted. React makes no guarantees about when styles are removed from the document.

import { GlobalStyles } from "restyle";

export default function Layout({ children }) {
  return (
    <>
      <GlobalStyles>
        {{
          body: {
            margin: 0,
            padding: 0,
            fontFamily: "sans-serif",
          },
        }}
      </GlobalStyles>
      {children}
    </>
  );
}