HN 표시: cn-variants – 3줄의 코드로 구성된 Tailwind CSS 변형
hackernews
|
|
📰 뉴스
#cn-variants
#tailwind css
#오픈소스
#유틸리티
#클래스 병합
원문 출처: hackernews · Genesis Park에서 요약 및 분석
요약
'cn-variants'는 Tailwind CSS 클래스 이름을 효율적으로 관리하기 위해 clsx와 tailwind-merge의 기능을 결합한 새로운 라이브러리입니다. 8.1kB의 가벼운 설치 크기를 자랑하며, 조건부 클래스 처리와 중복 및 충돌 해결을 지원하고 타입스크립트를 활용한 타입 안전성을 보장합니다. 또한, 사용자가 직접 입력한 스타일이 기본 스타일보다 우선 적용되도록 하여 React 컴포넌트의 유연성을 극대화하며 VS 코드 등에서 자동 완성을 지원합니다. 의존성 주요 버전 변경 시 반영되는 SemVer를 준수하여 안정적인 유지보수가 가능합니다.
본문
Tiny utilities for working with Tailwind CSS class names. Combines clsx + tailwind-merge with a typed variants helper. - Install Size - 8.1 kB(1 MB) - Vulns - Published npm install cn-variants pnpm add cn-variants yarn add cn-variants bun add cn-variants deno add npm:cn-variants vlt install cn-variants Tiny utilities for working with Tailwind CSS class names. Combines clsx + tailwind-merge with a typed variants helper. npm install cn-variants Merges class names using clsx and tailwind-merge. Handles conditionals, duplicates, and Tailwind conflicts. import { cn } from "cn-variants"; // Tailwind conflict resolution — last value wins cn("px-4 py-2", "px-6"); // → "py-2 px-6" // Conditionals cn("text-red-500", isActive && "text-blue-500"); // → "text-blue-500" (when isActive is true) // Object syntax cn("flex", { "gap-4": hasGap, "items-center": centered }); // → "flex gap-4 items-center" (when both are true) // Arrays cn(["rounded-lg", "shadow-md"], "p-4"); // → "rounded-lg shadow-md p-4" // Mixed — all clsx input types work cn("base", ["flex", "gap-2"], { "font-bold": isActive }, undefined, null, false); // → "base flex gap-2 font-bold" (when isActive is true) Creates a typed lookup function for Tailwind class variants. Returns "" for unknown keys at runtime, relying on TypeScript for compile-time safety. import { cn, variants } from "cn-variants"; const buttonVariant = variants({ primary: "bg-indigo-600 text-white border-none", secondary: "bg-transparent text-indigo-600 border border-indigo-600", danger: "bg-red-600 text-white border-none", }); const buttonSize = variants({ sm: "px-3 py-1 text-xs", md: "px-4 py-2 text-sm", lg: "px-6 py-3 text-base", }); The returned function exposes a frozen .options object with the original map, useful for deriving union types: type ButtonVariant = keyof typeof buttonVariant.options; // → "primary" | "secondary" | "danger" type ButtonSize = keyof typeof buttonSize.options; // → "sm" | "md" | "lg" interface ButtonProps { variant?: ButtonVariant; size?: ButtonSize; className?: string; children: React.ReactNode; } export function Button({ variant = "primary", size = "md", className, children }: ButtonProps) { return ( {children} ); } Callers can override any style through className — tailwind-merge ensures the caller's classes win: {/* bg-purple-600 overrides the primary variant's bg-indigo-600 */} For styles that depend on a combination of variants, use conditionals in cn : cn( "rounded-md font-medium", buttonVariant(variant), buttonSize(size), variant === "primary" && size === "lg" && "uppercase tracking-wide", variant === "danger" && "ring-2 ring-red-300", className, ); If you write wrapper functions around cn , you can import the ClassValue type directly: import { type ClassValue, cn } from "cn-variants"; function card(...classes: ClassValue[]) { return cn("rounded-lg border bg-white shadow-sm", ...classes); } To get autocomplete for class strings inside variants() and cn() , add them to the classFunctions setting in your editor's Tailwind CSS configuration. Install the Tailwind CSS IntelliSense extension, then add to your .vscode/settings.json : { "tailwindCSS.classFunctions": ["cn", "variants"] } Add to your project's .zed/settings.json : { "lsp": { "tailwindcss-language-server": { "settings": { "classFunctions": ["cn", "variants"] } } } } Install the Tailwind CSS plugin, then add to your tailwind.config.js : module.exports = { classFunctions: ["cn", "variants"], }; cn and variants are independent. If you only import variants , your bundler will tree-shake away cn and its dependencies (clsx, tailwind-merge), keeping your bundle minimal. cn-variants follows semver and pins to the current major of its dependencies: clsx ^2 and tailwind-merge ^3 . - Patch/minor upstream releases are absorbed automatically. No action needed on your part. - Major upstream releases may change observable behavior (e.g. how tailwind-merge resolves conflicting utilities). When this happens, cn-variants will release a new major version that bumps the dependency range. If cn("px-2", "px-4") returns a different result because of an upstream update, that's a breaking change from your perspective and will be treated as one. MIT
Genesis Park 편집팀이 AI를 활용하여 작성한 분석입니다. 원문은 출처 링크를 통해 확인할 수 있습니다.
공유