![onno](https://raw.github.com/wagerfield/onno/main/assets/onno.svg)
![License](https://img.shields.io/github/license/wagerfield/onno?style=flat-square&color=4C8&cacheSeconds=3600)
Tiny (596B) utility for composing class variants using clsx
pnpm add onno
Features
Usage
import { onno } from "onno"
const button = onno({
variants: {
size: {
sm: "h-8 px-1",
md: "h-10 px-2",
lg: "h-12 px-3",
},
intent: {
primary: "bg-blue-600 text-white",
secondary: "bg-gray-200 text-black",
},
disabled: "opacity-50",
},
})
const classes = button({ size: "md", intent: "primary", disabled: true })
Variants
Define variant names and the classes to be applied to them using the variants
config option:
const button = onno({
variants: {
disabled: "access denied",
hidden: ["barely", "visible"],
size: {
sm: ["pretty", "small"],
lg: "really large",
},
},
})
button()
button({})
button({ size: "sm" })
button({ disabled: true })
button({ hidden: true, size: "lg" })
Note that you cannot use className
as a variant key since it is reserved for applying additional classes:
const button = onno({
variants: {
className: "not allowed",
},
})
Defaults
Default variants can be set using the defaults
config option:
const button = onno({
defaults: {
hidden: true,
intent: "secondary",
},
variants: {
hidden: "barely visible",
intent: {
primary: "super punchy",
secondary: "quite bland",
},
size: {
sm: "pretty small",
lg: "really large",
},
},
})
button()
button({})
button({ hidden: false })
button({ intent: "primary" })
button({ size: "sm" })
Baseline Classes
Common classes can be applied using the baseline
config option:
const button = onno({
baseline: "solid base",
variants: {
size: {
sm: "pretty small",
lg: "really large",
},
},
})
button()
button({})
button({ size: "lg" })
Compound Classes
Apply classes when certain variants are combined using the compound
config option:
const button = onno({
variants: {
hidden: "barely visible",
size: {
sm: "pretty small",
md: "kinda normal",
lg: "really large",
},
},
compound: [
{
size: ["sm", "lg"],
className: ["compound", "one"],
},
{
size: "md",
hidden: true,
className: "compound two",
},
],
})
button()
button({})
button({ size: "md" })
button({ hidden: true })
button({ size: "lg" })
button({ size: "md", hidden: true })
Additional Classes
Additional classes can be applied using the className
option:
const button = onno({
baseline: "solid base",
variants: {
size: {
sm: "pretty small",
lg: "really large",
},
},
})
button()
button({ className: "with more" })
button({ className: "with more", size: "sm" })
Class Composition
Classes are applied in the following order:
baseline
variants
compound
className
Under the hood onno
uses clsx
to build the class list (see clsx
docs)
For convenience clsx
is exported from onno
so you can use it to compose classes:
import { onno, clsx } from "onno"
const button = onno({
variants: {
size: {
sm: "pretty small",
lg: "really large",
},
},
})
clsx("foo", ["bar", { baz: true }], button({ size: "sm" }))
Note that onno's className
option also accepts any clsx.ClassValue
so you can do:
import { onno, clsx } from "onno"
const button = onno({
variants: {
size: {
sm: "pretty small",
lg: "really large",
},
},
})
button({ size: "lg", className: ["foo", ["bar"], { baz: true }] })
TypeScript
Use the OnnoProps
type to infer variant props from an OnnoFunction
import { onno, type OnnoProps } from "onno"
export const button = onno({
variants: {
disabled: "not allowed",
size: {
sm: "pretty small",
lg: "really large",
},
},
})
export type ButtonProps = OnnoProps<typeof button>
export type ButtonSizeType = ButtonProps["size"]
export type ButtonDisabledType = ButtonProps["disabled"]
Note that inferred OnnoProps
also include the className
option alongside the variants:
export type ButtonClassNameType = ButtonProps["className"]
By default all variants inferred by OnnoProps
are optional. To require one or more variants, pass a union of required variant keys as the second argument to the OnnoProps
generic type:
import { onno, type OnnoProps } from "onno"
export const button = onno({
variants: {
disabled: "not allowed",
intent: {
primary: "super punchy",
secondary: "quite bland",
},
size: {
sm: "pretty small",
lg: "really large",
},
},
})
export type ButtonProps = OnnoProps<typeof button, "intent" | "size">
const buttonProps: ButtonProps = { size: "md" }
Tailwind CSS
If you are using the Tailwind CSS VSCode extension, add the following configuration to your workspace .vscode/settings.json
file:
{
"tailwindCSS.experimental.classRegex": [
["onno|clsx\\(([^)]*)\\)", "[\"'`]([^\"'`]*)[\"'`]"]
]
}
This will enable Tailwind's IntelliSense for both onno
and clsx
within your project! :tada:
![VSCode Tailwind CSS IntelliSense](https://raw.github.com/wagerfield/onno/main/assets/tailwindcss-vscode.png)
License
MIT © Matthew Wagerfield