styled-extract
TypeScript icon, indicating that this package has built-in type declarations

1.1.0 • Public • Published

styled-extract

A tiny utility to make type-safe variant components with vanilla extract and react.

Install

npm install --save styled-extract

Motivation

Vanilla extract is a great but if you're used to writing components with variant props using styled-system or stitches, it feels like writing boilerplate code.

This package is tiny, but borrows ideas from Emotion, Dessert Box and Stitches to turn this:

// Text.tsx
import { textRecipe, TextVariants } from './textRecipe.css.ts';

export const Text: FC<TextVariants> = ({ variant, color }) => (
  <div className="${textRecipe({
    variant,
    color
  })}">
    {children}
  </div>
)

Into this:

// Text.tsx
import styled from "styled"
import { textRecipe, variants } from './textRecipe.css.ts';

export const Text = styled("div", textRecipe, variants)();

Usage

You must export your variants from your .css.ts instead of using the immediately inside the recipe.

Your .css.ts file would look like:

// textRecipe.css.ts
export const variants = {
    variant: {
        title: {
            fontSize: "100px",
            fontWeight: 600
        },
        subtitle: {
            fontSize: "20px",
            fontWeight: 500
        },
    },
    color: {
        red: {
            background: "red",
        },
        blue: {
            background: "blue",
        },
    },
};

export const textRecipe = recipe({
    variants,
});

Then create your components with the styled tag:

// Text.tsx
import styled from "styled"
import { textRecipe, variants } from './textRecipe.css.ts';

export const Text = styled("div", textRecipe, variants)();

And use the component with its type safe props:

<Text variant="title" color="red">
  Groovy
</Text>

// Type error
<Text variant="not-a-real-option">
  Groovy
</Text>

It also supports a polymorphic as prop for simple use cases.

<Text variant="title" color="red" as="h1">
  Groovy
</Text>

Usage with Radix UI

Instead of:

import {labelRecipe, variants} from './textRecipe.css.ts';
import * as LabelPrimitive from '@radix-ui/react-label';

const Label = React.forwardRef<React.ElementRef<typeof LabelPrimitive>,
  React.ComponentProps<typeof LabelPrimitive>>((props, forwardedRef) => {
  const {className, variant, color, ...itemProps} = props;
  return (
    <LabelPrimitive.Root
      {...itemProps}
      ref={forwardedRef}
      className={`${labelRecipe({
        variant,
        color
      })} ${className}`}
    />
  );
});

You can write:

import {labelRecipe, variants} from './textRecipe.css.ts';
import * as LabelPrimitive from '@radix-ui/react-label';

export const Label = styled(LabelPrimitive.Root, labelRecipe, variants)();

Package Sidebar

Install

npm i styled-extract

Weekly Downloads

2

Version

1.1.0

License

MIT

Unpacked Size

12.7 kB

Total Files

11

Last publish

Collaborators

  • malii