Essentials
Jade Garden
If you worked plenty with Class Variance Authority or Tailwind Variants, you can skip most of the documentation. What is covered on this page are the essential enhancements Jade Garden has made in order to make UI development a breeze.
Class Variance Authority
Jade Garden has an equivalent cva
function to the beta version of Class Variance Authority.
The function accepts a single object as input.
import { cva } from "jade-garden/cva";
const h1 = cva({
base: "font-bold text-xl text-blue-200"
});
h1(); // "font-bold text-xl text-blue-200"
Slots Variance Authority
The equivalent to Tailwind Variants is the sva
function. Unlike Tailwind Variants, sva
does not ship with Tailwind Merge.
Under the hood, class names are merged with clsx
. It is more fair to compare sva
with the recently released version of Tailwind Variants lite.
In addition, the base
property has been renamed to slots
.
import { sva } from "jade-garden/sva";
const menu = sva({
slots: {
root: "flex flex-wrap",
submenu: ["absolute", "flex", "overflow-visible"]
},
variants: {
size: {
xs: {},
sm: {}
}
},
compoundSlots: [
{
slots: ["root"],
size: ["xs", "sm"],
class: "w-7 h-7 text-xs"
}
]
});
root({ size: "sm" }); // "flex flex-wrap w-7 h-7 text-xs"
submenu() // "absolute flex overflow-visible"
create
For the sake of convenience and performance, cva
and sva
functions use clsx
to merge class names by default.
However, if you need an escape hatch for class conflicts with a library like Tailwind Merge, or need a more performant merge algorithm like clsx/lite
,
you can create an instance of cva
and sva
with the createCVA
and createSVA
functions.
import { cn, createCVA } from "jade-garden";
export const cva = createCVA(cn);
const component = cva({
base: "base-class",
variants: {
size: {
small: "size-small",
medium: "size-medium"
},
variant: {
primary: "variant-primary",
secondary: "variant-secondary"
}
},
compoundVariants: [
{
size: "small",
variant: "primary",
class: "compound-small-primary"
}
]
});
component({ size: "small", variant: "primary" }); // "base-class size-small variant-primary compound-small-primary"
class-utils
unplugin-jade-garden
to work properly with Tailwind CSS.In addition to cva
and sva
functions, there are utility functions that support modifying class names:
cm
: Conditional class merging withinclude
andexclude
options.cn
: Alias for clsx/lite.cx
: Alias for clsx.- Plugin Functions:
getClasses
: A function that generates class names based on acva
orsva
configuration.prefixClasses
: A utility to simplify the maintenance of prefixed CSS classes.traits
: Generates CSS class names and data attributes.
import { cm } from "jade-garden/class-utils";
// cm (Class Manipulator)
const specialClasses = cm(
"button-primary focus:outline-none",
{
exclude: "button-primary",
include: "custom-animation"
}
);
// "focus:outline-none custom-animation" - removed "button-primary" and added "custom-animation"
define
Jade Garden provides extensibility and portability of your cva
and sva
configurations with defineCVA
and defineSVA
.
These helper function provide better TypeScript support and IntelliSense that makes it possible to reuse your configurations beyond any project.
import { cva, defineCVA } from "jade-garden/cva";
export const buttonConfig = defineCVA({
name: "button",
base: "rounded-full",
variants: {
intent: {
primary: [
"bg-blue-500",
"text-white",
"border-transparent",
"hover:bg-blue-600"
],
secondary: [
"bg-white",
"text-gray-800",
"border-gray-400",
"hover:bg-gray-100"
]
},
size: {
small: [
"text-sm",
"py-1",
"px-2"
],
medium: [
"text-base",
"py-2",
"px-4"
]
}
},
compoundVariants: [
{
intent: "primary",
size: "medium",
class: "uppercase"
}
],
defaultVariants: {
intent: "primary",
size: "medium"
}
});
const button = cva(buttonConfig);
TypeScript
Similar to Class Variance Authority and Tailwind Variants, Jade Garden ships VariantProps
.
In addition, there are other utility types that help build upon your design system.
ClassStrings
: Represents the minimum structure to work with class names.ClassValue
: Represents the values thatclsx
can process to generate a class name string.MergeFn
: Represents a function that merges class names.Traits
: Helps define the structure for configuring and usingtraits
.VariantProps
: Extracts the variant-related props from a component's overall props type.
import type { VariantProps } from "jade-garden";
import { cva } from "./cva";
const button = cva({
name: "button",
base: "rounded-full",
variants: {
intent: {
primary: [
"bg-blue-500",
"text-white",
"border-transparent",
"hover:bg-blue-600"
],
secondary: [
"bg-white",
"text-gray-800",
"border-gray-400",
"hover:bg-gray-100"
]
},
size: {
small: [
"text-sm",
"py-1",
"px-2"
],
medium: [
"text-base",
"py-2",
"px-4"
]
}
},
compoundVariants: [
{
intent: "primary",
size: "medium",
class: "uppercase"
}
],
defaultVariants: {
intent: "primary",
size: "medium"
}
});
/**
* {
* intent?: "primary" | "secondary";
* size?: "small" | "medium";
* }
*/
type ButtonProps = VariantProps<typeof button>;
Unplugin Jade Garden
If you want to create an extensible design system with Tailwind CSS and Jade Garden, use unplugin-jade-garden
to generate CSS that Tailwind can compile.
You would utilize the Plugin Functions from class-utils
and define
functions to generate CSS with the plugin.
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import jadeGarden from "unplugin-jade-garden/vite";
import { alertConfig, buttonConfig } from "./src";
export default defineConfig({
build: {
lib: {
entry: "./src/index.ts"
}
},
plugins: [
jadeGarden({
styleConfigs: {
components: [alertConfig, buttonConfig]
},
entry: "./styles/app.css"
}),
react(),
tailwindcss()
]
});