TW-Classed

Composing Components

Learn how to compose components with TW-Classed

Composing Components

Composing one Classed component into another.

Classed Components can be composed via the classed function.

First argument composition

The first argument of the classed function is the Classed component to be composed. All variants and classNames are inherited.

import { classed } from "@tw-classed/react";

const BaseButton = classed("button");

const CheckoutButton = classed(
  BaseButton,
  "bg-blue-500 text-white font-bold py-2 px-4 rounded",
  {
    variants: {
      size: {
        sm: "text-sm",
        lg: "text-lg",
      },
    },
    defaultVariants: {
      disabled: "opacity-50 cursor-not-allowed",
    },
  }
);

() => (
  <>
    <BaseButton>Base Button</BaseButton>
    <CheckoutButton size="sm">Checkout Button</CheckoutButton>
  </>
);

Any argument composition

The classed function accepts any number of arguments and will compose them in order. All classNames and variants are inherited.

import { classed } from "@tw-classed/react";

const SizeButton = classed("button", {
  variants: {
    size: {
      sm: "text-sm",
      lg: "text-lg",
    },
  },
  defaultVariants: {
    size: "sm",
  },
});

const ColorButton = classed("button", {
  variants: {
    color: {
      red: "text-red-500",
      blue: "text-blue-500",
    },
  },
  defaultVariants: {
    color: "red",
  },
});

const Anchor = classed("a", "flex items-center", SizeButton, ColorButton);
// Anchor will be rendered as an `a` element inheriting all classNames and variants from SizeButton and ColorButton

() => (
  <>
    <Anchor size="lg" color="blue">
      Anchor
    </Anchor>
  </>
);

Using the render prop

The render prop can be used to change the underlying element of a Classed component. This is powered by the useRender hook from @base-ui/react.

import { classed } from "@tw-classed/react";

const BaseButton = classed(
  "button",
  "bg-blue-500 text-white",
  "hover:bg-blue-400"
);

() => (
  <BaseButton render={<a href="https://google.com" />}>
    Link Button
  </BaseButton>
);

Using render as a function

The render prop also accepts a function that receives the props and allows you to have full control over the rendered element:

import { classed } from "@tw-classed/react";

const Button = classed("button", {
  base: "px-4 py-2 rounded",
  variants: {
    color: {
      blue: "bg-blue-500 text-white",
      red: "bg-red-500 text-white",
    },
  },
});

() => (
  <Button
    color="blue"
    render={(props) => (
      <a {...props} href="/contact">
        Contact Us
      </a>
    )}
  >
    Click me
  </Button>
);

Composing non-classed components

Classed components can be composed with non-classed components as the first argument to the classed function.

import { Link } from "react-router-dom";
import { classed } from "@tw-classed/react";

// First argument to classed
const LinkButton = classed(Link, "bg-blue-500 text-white");

() => <LinkButton to="/checkout">Checkout</LinkButton>;

Note: When wrapping a custom component (non-intrinsic element), the render prop is not available. The component uses its own props directly.

On this page