A typesafe, class-variance-authority-based, styled-components-like library for authoring React components
npm
npm i --save styled-cva
pnpm
pnpm add styled-cva
bun
bun add styled-cva
basic
import tw from "styled-cva";
const StaticButton = tw.button`
bg-primary rounded-xl cursor-pointer
`;
// ...
<StaticButton>Click Me</StaticButton>;
variants
import tw from "styled-cva";
const VariantButton = tw.button.cva("btn-base-class", {
variants: {
// smart disappearing props:
// variant keys starting with $ will not be sent to the DOM,
// this avoids extraneous props warning
$variant: {
primary: "btn-primary-class",
secondary: "btn-secondary-class",
},
},
});
// ...
// $variant is infered to 'primary' | 'secondary'
<VariantButton $variant="primary">Click Me</VariantButton>;
// actual element in the dom will be:
// <button class="btn-primary-class">Click Me</button>
proxy
import Link from "next/link";
const Button = tw.button.cva("btn", {
variants: {
$variant: {
primary: "btn-primary",
secondary: "btn-secondary",
},
},
});
// ...
// works with known jsx elements
<Button $as="a" href="/some/url">
I'm a link that looks like a button
</Button>;
// also with custom components
<Button $as={Link} href="/some/url">
I'm a link that looks like a button
</Button>;
For tailwindcss extension support, add this to your vscode settings.json
// tailwindcss intelisense settings
"tailwindCSS.emmetCompletions": true,
"tailwindCSS.includeLanguages": {
"typescript": "javascript", // if you are using typescript
"typescriptreact": "javascript" // if you are using typescript with react
},
"tailwindCSS.experimental.classRegex": [
"tw`([^`]*)", // tw`...`
"tw\\.[^`]+`([^`]*)`", // tw.xxx<xxx>`...`
"tw\\(.*?\\).*?`([^`]*)", // tw(Component)<xxx>`...`
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
],
"editor.quickSuggestions": {
"strings": true // forces VS Code to trigger completions when editing "string" content
},
License - Apache-2.0