npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

tiwi

v1.0.14

Published

React library to create components with Tailwind styles baked in.

Downloads

617

Readme

tiwi · GitHub license npm version

Tiwi is a React library that makes it easy to create components with Tailwind styles baked in. This makes it straightforward to preserve the separation of concern between structure and style, similar to styled-components. It also comes with a powerful variants system for more advanced use cases.

This library works with both React on the web and React Native.

Getting started

1. Tailwind

Install and configure TailwindCSS in your project.

2. Tiwi

npm install tiwi

3. VSCode

For the best experience, install the official Tailwind CSS Intellisense extension.

The following configuration will allow the extension to work with Tiwi:

"editor.quickSuggestions": {
  "strings": "on" // As-you-type suggestions within strings.
},
"tailwindCSS.experimental.classRegex": [
  [
    "(?:tiwi|tw)[.(][^`]+([^;]*)",
    "[\"'`\\}]([^\"'`\\$]*)[\"'`\\$]"
  ]
]

Basic usage

Import Tiwi in your component file:

import tiwi from "tiwi";

You can now create Tiwi components:

const Header = tiwi.h1`
  text-3xl
  text-blue-600
`;

const Button = tiwi.button`
  rounded
  bg-blue-300
`;

These can be used like any other component:

<Button />

// Renders as:
// <button class="rounded bg-blue-300" />

Classes can still be overridden inline:

<Button className="bg-red-300" />

// Renders as:
// <button class="rounded bg-red-300" />

Other props work as expected:

<Button type="submit">Submit</Button>

// Renders as:
// <button class="rounded bg-blue-300" type="submit">Submit</button>

Tiwi components can be further extended:

const BigButton = tiwi(Button)`
  text-lg
`;

// Renders as:
// <button class="rounded bg-blue-300 text-lg" />

When extending, styles can be overwritten:

const RedButton = tiwi(Button)`
  bg-red-300
`;

// Renders as:
// <button class="rounded bg-red-300" />

Any component with a className prop can be styled:

const SubmitButton: FC<{className?: string}> = props => {
  return (
    <button className={props.className} type="submit">
      Submit
    </button>
  );
};

const RedSubmitButton = tiwi(SubmitButton)`
  bg-red-300
`;

// Renders as:
// <button class="bg-red-300" type="submit">Submit</button>

Variants

What makes Tiwi so powerful is the built-in support for variants. It enables the style of a component to be changed along multiple dimensions without creating every permutation separately.

Here's a simple variant to support multiple sizes:

const SizeButton = tiwi.button`
  m-1
  p-2
  text-normal

  ${{
    medium: `
      p-3
      text-lg
    `,
    large: `
      p-5
      text-xl
    `,
  }}
`;

The desired variants can be provided in different ways:

<SizeButton />;

// Renders as:
// <button class="m-1 p-2 text-normal" />

<SizeButton variants="medium" />;
<SizeButton variants={["medium"]} />;
<SizeButton variants={{medium: true}} />;

// All render as:
// <button class="m-1 p-3 text-lg" />

If multiple variants overlap, the last one to be declared wins:

<SizeButton variants={["medium", "large"]} />;
<SizeButton variants={["large", "medium"]} />;
<SizeButton variants={{medium: true, large: true}} />;

// All render as:
// <button class="m-1 p-5 text-xl" />

Variants can be specified along separate dimensions:

const FlexButton = tiwi.button`
  p-2
  text-normal
  bg-blue-300

  ${{
    medium: `
      p-3
      text-lg
    `,
    large: `
      p-5
      text-xl
    `,
  }}

  ${{
    primary: `
      bg-green-300
    `,
    critical: `
      bg-red-300
    `,
  }}
`;
<FlexButton variants={["medium", "critical"]} />;
<FlexButton variants={{medium: true, critical: true}} />;

// Both render as:
// <button class="p-3 text-lg bg-red-300" />

Variants can directly match some of the component's props:

const Button = tiwi.button`
  bg-blue-500

  ${{
    isDisabled: `bg-neutral-200`,
  }}
`;

const MyComponent: FC<{isDisabled?: boolean}> = props => {
  return <Button variants={props}>Continue</Button>;
};

Base style and variants can be declared in any order:

const FlexButton = tiwi.button`
  text-normal
  ${{
    medium: `text-lg`,
    large: `text-xl`,
  }}

  bg-blue-300
  ${{
    primary: `bg-green-300`,
    critical: `bg-red-300`,
  }}
`;

TypeScript

Tiwi is fully compatible with TypeScript and both props and variants are strongly typed automatically.

On top of that, an explicit variant type can be provided:

type Size = "small" | "medium";

const SizeButton = tiwi.button<Size>`
  text-normal
  ${{medium: `text-medium`}}
`;

const MyComponent: FC<{size?: Size}> = props => {
  return <SizeButton variants={props.size}>Press me!</SizeButton>;
};

The opposite (extracting the variants type) is also possible:

import tiwi, {VariantsOf} from "tiwi";

const SizeButton = tiwi.button`
  text-normal
  ${{
    medium: `text-medium`,
    large: `text-large`,
  }}
`;

type Variants = VariantsOf<typeof SizeButton>; // "medium" | "large".

React Native

Tiwi is compatible with React Native. It requires NativeWind to be installed.

React Native elements can then be styled in the same way:

import {View, Text} from "react-native";
import tiwi from "tiwi";

const Avatar = tiwi(View)`
  size-10
  rounded-full
`;

const Title = tiwi(Text)`
  text-neutral-900
  dark:text-white
`;

Full example

// tooltip.tsx

import {FC, PropsWithChildren, ReactNode} from "react";
import tiwi from "tiwi";

//
// Props.
//

type TooltipVariant = "normal" | "important";

interface TooltipProps extends PropsWithChildren {
  variant?: TooltipVariant;
  icon: ReactNode;
}

//
// Style.
//

const Layout = tiwi.div<TooltipVariant>`
  flex
  flex-row

  rounded
  p-2
  gap-1

  bg-neutral-200

  ${{
    important: `bg-red-200`,
  }}
`;

const Icon = tiwi.div`
  size-5
`;

const Text = tiwi.div`
  text-neutral-900
  font-medium
`;

//
// Component.
//

export const Tooltip: FC<TooltipProps> = props => {
  const {variant, icon, children} = props;
  return (
    <Layout variants={variant}>
      <Icon>{icon}</Icon>
      <Text>{children}</Text>
    </Layout>
  );
};

Acknowledgements

This library was inspired by Tailwind-Styled-Component and borrows some of its ideas. It also heavily relies on tailwind-merge for the underlying class manipulation and shares the same limitations.

License

Tiwi is MIT licensed.