restyle

repository·main·Indexed 19 days ago

https://github.com/souporserious/restyle

A zero-config, zero-dependency CSS-in-JS library for React that generates atomic CSS on-demand. It is lightweight (2.2kb gzipped) and supports Server and Client Components, React Suspense, and streaming. Features include a `styled` utility for components, a `css` prop via JSX pragma, dynamic style props, media queries, keyframes, and global styles for theming.

Tokens
9.9K
Snippets
40
Records
43
Agent score
62%

What's inside restyle

  1. Create components with dynamic style props

    main

    The styled utility accepts a second argument: a style resolver function. This function allows you to return styles based on props passed to the component. These are referred to as style props.

    Accessing Style Props

    Use the first parameter of the style resolver function to access style props. A proxy is used to differentiate these from standard component props.

    Accessing Component Props

    Use the second parameter of the style resolver function to access standard component props that are not intended for styling (e.g., disabled, onClick).

    import { styled } from 'restyle'
    
    interface ButtonStyleProps {
      backgroundColor: string
      color: string
    }
    
    // styleProps contains the style-specific props
    // props contains the rest of the component's props
    const Button = styled('button', (styleProps: ButtonStyleProps, props) => ({
      backgroundColor: styleProps.backgroundColor,
      color: styleProps.color,
      opacity: props.disabled ? 0.6 : 1,
    }))
    import { styled } from 'restyle'
    
    interface ButtonStyleProps {
      backgroundColor: string
      color: string
    }
    
    const Button = styled('button', (styleProps: ButtonStyleProps, props) => ({
      backgroundColor: styleProps.backgroundColor,
      color: styleProps.color,
      opacity: props.disabled ? 0.6 : 1,
    }))
  2. Implement theming using CSS variables and `GlobalStyles`

    main

    Theming is achieved by defining CSS variables within a GlobalStyles component (often targeting :root) and consuming those variables in your styled components.

    import { GlobalStyles, styled } from 'restyle'
    
    const Container = styled('div', {
      backgroundColor: 'var(--background)',
      color: 'var(--foreground)',
    })
    
    export default function App() {
      return (
        <>
          <GlobalStyles>
            {{
              ':root': {
                '--background': '#ffffff',
                '--foreground': '#000000',
              },
              '@media (prefers-color-scheme: dark)': {
                ':root': {
                  '--background': '#000000',
                  '--foreground': '#ffffff',
                },
              },
            }}
          </GlobalStyles>
          <Container>Themed Content</Container>
        </>
      )
    }
  3. How restyle works: Atomic CSS and On-Demand Injection

    main

    Restyle uses an atomic CSS approach to provide efficient, scalable styling:

    1. Styles Parsing: It parses a CSS object and generates unique atomic class names for every property-value pair.
    2. Deduplication: Class names are hashed and cached to prevent collisions and reduce CSS size.
    3. Atomic CSS: Styles are broken into reusable units. If multiple elements share a property (e.g., padding: '1rem'), they share the same atomic class.
    4. On-Demand Injection: Styles are only injected into the DOM when the component is rendered. The css() function returns both the classNames (string) and a Styles component that must be rendered to inject the <style> tag.
    import { css } from 'restyle'
    
    // 1. Parsing and generating class names/styles
    const [classNames, Styles] = css({
      padding: '1rem',
      backgroundColor: 'peachpuff',
    })
    
    // 2. Usage in a component
    export default function OnDemandStyles() {
      const [classNames, Styles] = css({
        padding: '1rem',
        backgroundColor: 'papayawhip',
      })
    
      return (
        <div className={classNames}>
          Hello World
          <Styles />
        </div>
      )
    }
  4. Use the css prop via JSX pragma

    main

    You can use the css prop directly on JSX elements by adding the @jsxImportSource restyle pragma at the top of your file. This allows for colocated inline styles without manual class management.

    /** @jsxImportSource restyle */
    
    export default function MyComponent() {
      return (
        <div
          css={{
            padding: '1rem',
            backgroundColor: 'peachpuff',
          }}
        >
          Hello World
        </div>
      )
    }
  5. Implement Theming using CSS Variables and `GlobalStyles`

    main

    You can implement a theme by defining CSS variables within the GlobalStyles component. These variables can then be consumed by styled components or the css prop.

    import { GlobalStyles, styled } from 'restyle'
    
    const Container = styled('div', {
      backgroundColor: 'var(--background)',
      color: 'var(--foreground)',
      minHeight: '100vh',
      display: 'grid',
      placeItems: 'center',
    })
    
    const Button = styled('button', {
      padding: '0.5rem 1rem',
      borderRadius: '0.1rem',
      backgroundColor: 'var(--button-background)',
      color: 'var(--button-foreground)',
      border: 'none',
      cursor: 'pointer',
    })
    
    export default function App() {
      return (
        <>
          <GlobalStyles>
            {{
              ':root': {
                '--background': '#ffffff',
                '--foreground': '#000000',
                '--button-background': '#007bff',
                '--button-foreground': '#ffffff',
              },
              '@media (prefers-color-scheme: dark)': {
                ':root': {
                  '--background': '#000000',
                  '--foreground': '#ffffff',
                  '--button-background': '#1a73e8',
                  '--button-foreground': '#ffffff',
                },
              },
            }}
          </GlobalStyles>
          <Container>
            <Button>Themed Button</Button>
          </Container>
        </>
      )
    }
  6. Enable the `css` prop via pragma configuration

    main

    To use the css prop directly on elements, you must configure the JSX import source. You can do this globally in tsconfig.json or locally at the top of a file.

    Global configuration (tsconfig.json):

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

    Local configuration (File Pragma):

    /** @jsxImportSource restyle */
    
    export default function CSSProp() {
      return (
        <div
          css={{
            padding: '1rem',
            backgroundColor: 'peachpuff',
          }}
        >
          Hello World
        </div>
      )
    }
  7. Use the `css` prop for direct element styling

    main

    You can style elements directly using the css prop. To use this, you must configure the JSX pragma so the compiler knows to use restyle as the import source.

    Set jsxImportSource to restyle in your TypeScript configuration:

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

    Option 2: File-level Pragma

    Add the pragma to the top of your file:

    /** @jsxImportSource restyle */
    
    export default function CSSProp() {
      return (
        <div
          css={{
            padding: '1rem',
            backgroundColor: 'peachpuff',
          }}
        >
          Hello World
        </div>
      )
    }
  8. Start the development server

    main

    To run the project locally in development mode, use your preferred package manager to execute the dev script. Once running, the application is accessible at http://localhost:3000.

    npm run dev
    # or
    yarn dev
    # or
    pnpm dev
    # or
    bun dev
  9. Implement component variants using style props

    main

    Variants can be implemented by combining the styled utility with a style resolver function that maps a specific prop (like variant) to a set of predefined styles.

    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 }) => ({
      padding: '1.5rem 2rem',
      borderRadius: '0.5rem',
      color: 'white',
      ...variantStyles[props.variant],
    }))
  10. Create component variants using style props

    main

    Variants can be implemented by using the style props pattern. You define a mapping of variant names to CSS objects and use the variant prop to select the correct styles in the styled resolver.

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