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 that have been made in order to make UI development a breeze.
Class Variance Authority
Jade Garden has a cva function equivalent 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 requires a slots property in order to work.
The slots property accepts a value of string[] to intentionally define the keys in your base property.
If you have a base property that is not included in slots, the function will NOT return a named function that you specified in base.
unplugin-jade-garden.
The base properties that are defined in slots are optional for developers who may only design some, but not all of the components.// ! Does not work
const brokenComponent = sva({
base: {
root: "",
title: "",
message: "",
}
});
// 'root', 'title', and 'message' is undefined
const { root, title, message } = brokenComponent();
// * Works
const component = sva({
slots: ["root", "title", "message"]
})
const { root, title, message } = component();
In addition, sva does not ship with Tailwind Merge.
Under the hood, class names are merged with cx, and it is more fair to compare sva with the recently released version of Tailwind Variants lite.
import { sva } from "jade-garden/sva";
const menu = sva({
base: {
root: "flex flex-wrap",
submenu: ["absolute", "flex", "overflow-visible"]
},
slots: ["root", "submenu"],
variants: {
size: {
xs: {},
sm: {}
}
},
compoundSlots: [
{
slots: ["root"],
size: ["xs", "sm"],
class: "w-7 h-7 text-xs"
}
]
});
menu().root({ size: "sm" }); // "flex flex-wrap w-7 h-7 text-xs"
menu().submenu() // "absolute flex overflow-visible"
create
For the sake of convenience and performance, cva and sva functions uses cx 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 cn.
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({ mergeFn: 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 withincludeandexcludeoptions.cn: Modified version of clsx/lite.cx: Modified version of clsx.- Plugin Functions:
prefixes: A utility to simplify the maintenance of prefixed CSS classes.traits: Generates CSS class names and HTML 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"
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 injade-garden.ClassValue: This is the type fromclsxthat represents input that can be used to generate a class name.CreateOptions: The options used to modify your class names forcreateCVAandcreateSVA.MergeFn: The merge function signature forcreateCVAandcreateSVA.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 OR the cva and sva style configurations to use in your local project.
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import jadeGarden from "unplugin-jade-garden/vite";
import { alert, button } from "./src";
export default defineConfig({
build: {
lib: {
entry: "./src/index.ts"
}
},
plugins: [
jadeGarden({
components: {
components: [alertConfig, buttonConfig]
},
entry: "./styles/app.css"
}),
react(),
tailwindcss()
]
});