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

restyle

v2.3.0

Published

The simplest way to add CSS to your React components.

Downloads

5,744

Readme

Features

  • Generates atomic class names
  • Works in Server and Client Components
  • Compatible with Suspense and streaming
  • Deduplicates styles across environments
  • Encourages encapsulation
  • Supports css prop with JSX pragma
  • Loads styles on demand
  • Allows shipping CSS in NPM packages
  • 1.5kb minified and gzipped

Installation

npm install restyle
import { styled } from 'restyle'

export const Box = styled('div', {
  padding: '1rem',
  backgroundColor: 'peachpuff',
})

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

How it Works

Restyle leverages React's new ability to hoist style elements by generating atomic CSS on-demand to provide a flexible and efficient styling solution for React components.

Here's a high-level overview of how it works:

  1. Styles Parsing: Restyle takes a styles object of CSS and parses it, generating atomic class names for each unique style property and value pair:
import { css } from 'restyle'

const [classNames, Styles] = css({
  padding: '1rem',
  backgroundColor: 'peachpuff',
})

// classNames: 'x1y2 x3z4'
// Styles: <style>.x1y2{padding:1rem}.x3z4{background-color:peachpuff}</style>
  1. Class Names Generation and Deduplication: Atomic class names are generated using a hashing function to ensure uniqueness and prevent collisions. Class names are cached per request, optimizing performance and reducing the overall size of the generated CSS:
import { css } from 'restyle'

const [classNames] = css({
  padding: '1rem',
  backgroundColor: 'tomato',
})

// Example output: 'x1y2 xfg3'
  1. Atomic CSS: By breaking down styles into atomic units, it allows for highly reusable class names, making it easy to manage and override styles while reducing the overall size of the CSS produced:
import { css } from 'restyle'

const styles = {
  padding: '1rem',
  backgroundColor: 'rebeccapurple',
}

const [classNames, Styles] = css(styles)

// classNames: 'x1y2 x4z1'
// Reuse class names for other elements
const buttonStyles = {
  ...styles,
  border: '1px solid black',
}

const [buttonClassNames, ButtonStyles] = css(buttonStyles)

// buttonClassNames: 'x1y2 x4z1 x5a6'
  1. On-Demand Style Injection: Styles are only added to the DOM when the component or element is rendered:
import { css } from 'restyle'

export default function OnDemandStyles() {
  const [classNames, Styles] = css({
    padding: '1rem',
    backgroundColor: 'papayawhip',
  })

  return (
    <div className={classNames}>
      Hello World
      <Styles />
    </div>
  )
}
  1. Integration with JSX Pragma: Easily add support for the css prop via the JSX pragma, allowing colocated inline CSS styles directly on JSX elements.
/** @jsxImportSource restyle */

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

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>

[!IMPORTANT] 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>
  )
}

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>
  )
}

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, Styles may 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 Page() {
  return (
    <GlobalStyles>
      {{
        body: {
          margin: 0,
          padding: 0,
          fontFamily: 'sans-serif',
        },
      }}
    </GlobalStyles>
  )
}

Acknowledgments

This project is inspired by and builds upon the ideas and work of several other projects in the CSS-in-JS ecosystem:

  • The React team for the style hoisting feature which makes this library possible
  • Glamor for introducing the css prop
  • Styled-Components for introducing the styled function
  • Emotion for types and the modern JSX pragma
  • CXS for atomic CSS generation
  • Fela for their approach to deterministic atomic class name ordering
  • Otion for the regex to parse unitless CSS properties

Thank you to WebReflection for the restyle NPM package name.

Development

In one terminal, run the following command to build the library and watch for changes:

npm install
npm run dev

In another terminal, run the following command to start the development server for the site:

cd site
npm install
npm run dev