Stoop
GitHub
/

styled

Create styled components with type-safe props and variants

Usage

import { styled } from "./theme";

const Button = styled("button", {
  padding: "$medium $large",
  borderRadius: "$default",
  cursor: "pointer",
});

With Variants

const Button = styled("button", {
  padding: "$medium $large",
  variants: {
    variant: {
      primary: {
        backgroundColor: "$primary",
        color: "$background",
      },
      secondary: {
        backgroundColor: "$background",
        border: "1px solid $border",
      },
    },
    size: {
      small: {
        padding: "$small $medium",
      },
    },
  },
});

Polymorphic Components

Use the as prop to render different elements:

const Box = styled("div", {
  padding: "$medium",
});

<Box as="section">Content</Box>

Dynamic Styles with css Prop

Use the css prop to apply dynamic styles to styled components:

const Button = styled("button", {
  padding: "$medium $large",
  borderRadius: "$default",
});

function MyComponent() {
  const isActive = true;

  return (
    <Button
      css={{
        marginTop: "$large",
        backgroundColor: isActive ? "$primary" : "$background",
        "&:hover": {
          opacity: 0.8,
        },
      }}
    >
      Dynamic Button
    </Button>
  );
}

The css prop merges with the component's base styles and supports:

Merging order: Base styles → Variants → CSS properties as props → css prop (later styles override earlier ones)

  1. Base styles apply first
  2. Variant styles merge with base styles
  3. CSS properties passed as props (e.g., marginTop="$large") merge next
  4. The css prop merges last (highest priority)

CSS Properties as Props

CSS properties passed as props convert to CSS styles:

const Box = styled("div", {
  padding: "$medium",
});

<Box marginTop="$large" padding="$small">
  Content
</Box>

CSS properties passed as props merge before the css prop, enabling prop-based overrides.

Component Targeting

Styled components expose a .selector property for targeting in nested styles:

const Button = styled("button", {
  padding: "$medium",
  backgroundColor: "$primary",
});

const Card = styled("div", {
  padding: "$large",
  [Button.selector]: {
    marginTop: "$medium",
  },
});

The selector is based on the component's base styles hash, making it stable across renders even if variants or CSS props change.