react-twc Documentation

repository·main·Indexed 23 days ago

https://github.com/gregberge/twc

A lightweight (0.49kb) utility for creating reusable React components styled with Tailwind CSS. It reduces boilerplate by replacing traditional forwardRef patterns with a factory that supports tagged template literals, dynamic prop-based styling, and an asChild prop for composition. Features include integration with tailwind-merge and cva, transient prop filtering to prevent invalid HTML attributes, and the .attrs() method for attaching static or dynamic attributes.

Tokens
7.2K
Snippets
22
Records
39
Agent score
80%

What's inside react-twc

  1. Introduction to twc

    main
    twc is a library designed to make using Tailwind CSS with React more productive. It solves the problem of repetitive and verbose component creation when trying to reuse Tailwind class names. Instead of manually merging class names using utilities like clsx or tailwind-merge inside a forwardRef component, twc allows you to create reusable components directly from HTML elements using tagged template literals.
  2. Key features of react-twc

    main

    TWC (Tailwind CSS + React Components) provides several out-of-the-box capabilities for building components:

    • Lightweight: The package is approximately 0.49kb.
    • Autocompletion: Supports autocompletion in most editors.
    • Prop-based Styling: Ability to adapt styles based on component props.
    • asChild Prop: Reuse classes using the asChild pattern.
    • Universal Compatibility: Works with all components and is compatible with React Server Components (RSC).
    • Tooling Support: First-class support for tailwind-merge and cva (Class Variance Authority).
  3. Reuse classes on custom components with the `asChild` prop

    main

    The asChild prop allows you to apply the Tailwind CSS classes defined on a twc component to its immediate child element instead of rendering the default HTML tag. This is useful for styling third-party components (like next/link) using the styles already defined in your twc components.

    Internally, twc uses the Radix UI Slot component to implement this behavior. When asChild is present, the twc component will not render its own tag; instead, it will pass its props (including the generated classes) to the child element.

    import NextLink from "next/link";
    import { Anchor } from "./components/anchor";
    
    export default () => (
      <Anchor asChild>
        <NextLink href="/">Go home</NextLink>
      </Anchor>,
    );
  4. Props interpolation support in react-twc

    main
    Currently, react-twc does not support props interpolation within the class definitions. To handle dynamic classes based on props, you should pass the logic as a function at the top level of the component instead of attempting to interpolate them within the component's class definition.
  5. Automatic ref forwarding in twc

    main
    One of the core features of twc is that it automatically handles ref prop forwarding for all generated components. When you create a component using the twc tagged template literals (e.g., twc.div or twc.span), you do not need to manually implement React.forwardRef. You can pass a ref directly to the resulting component, and it will be correctly attached to the underlying DOM element.
  6. Key differences between react-twc and classed-components

    main

    react-twc is not a direct port of styled-components for classes. It is designed to follow modern practices while maintaining a small footprint. Key features that distinguish it from similar libraries like classed-components include:

    • Support for the asChild prop.
    • The ability to specify your own custom compose function.
  7. Use react-twc without Tailwind CSS

    main
    While react-twc is designed to improve productivity when using Tailwind CSS with React, it is not strictly tied to it. Because the library creates class-based components, you can use it to manage CSS classes in any project, even those not using Tailwind CSS.
  8. Adapt classes based on props in `twc`

    main

    You can pass a function to a twc component factory to dynamically adapt Tailwind classes based on the component's props. This is useful for implementing states like primary, disabled, or active.

    To ensure these props are not passed down to the underlying DOM element (preventing invalid HTML attributes), prefix them with a $ (e.g., $primary). These are known as transient props.

    When defining types for these components, use TwcComponentProps<"element"> to include the standard props accepted by twc components (which includes asChild and className).

    import { twc, TwcComponentProps } from "react-twc";
    
    type ButtonProps = TwcComponentProps<"button"> & { $primary?: boolean };
    
    const Button = twc.button<ButtonProps>((props) => [
      "font-semibold border border-blue-500 rounded",
      props.$primary ? "bg-blue-500 text-white" : "bg-white text-gray-800",
    ]);
  9. Extend component classes using the `className` prop

    main

    All twc components accept a className prop that allows you to extend the base classes defined on the component. Because twc uses clsx internally to merge classes, you can pass any format supported by clsx, including strings, arrays, objects, or nested structures.

    import { twc } from 'react-twc'
    
    const Title = twc.h2`text-2xl font-bold`;
    
    // Strings
    <Title className="uppercase" />
    
    // Array
    <Title className={[false, 0, "uppercase"]} />
    
    // Objects
    <Title className={{ uppercase: true }} />
    
    // Nesting
    <Title className={[{ uppercase: true }, "underline"]} />
  10. Style any component with twc

    main

    You can use twc to style any component (your own or from third-party libraries like Radix or React Aria) as long as the component accepts a className prop. To do this, pass the component to the twc function and append your Tailwind CSS classes using tagged template literals.

    import * as HoverCard from "@radix-ui/react-hover-card";
    import { twc } from "react-twc";
    
    const HoverCardContent = twc(
      HoverCard.Content,
    )`data-[side=bottom]:animate-slideUpAndFade data-[side=right]:animate-slideLeftAndFade data-[side=left]:animate-slideRightAndFade data-[side=top]:animate-slideDownAndFade w-[300px] rounded-md bg-white p-5 shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] data-[state=open]:transition-all`;