Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
A tiny, performant, utility for constructing variant based CSS class strings.
NPM:
npm i cvu
Yarn:
yarn add cvu
PNPM:
pnpm i cvu
If you're a Tailwind user, here are some additional (optional) steps to get the most out of cvu
.
You can enable autocompletion inside cvu
using the steps below:
VSCode
settings.json
:{
"tailwindCSS.experimental.classRegex": [
[
"cvu\\s*(?:<[\\s\\S]*?>)?\\s*\\(([^)]*)\\)",
"[\"'`]([^\"'`]*).*?[\"'`]"
]
]
}
Although cvu
's API is designed to help you avoid style conflicts, there is still a small margin of error.
If you're keep to lift that burden altogether, check out tailwind-merge
package.
For bulletproof components, wrap your cvu
calls with twMerge
.
import { cvu, type VariantProps } from 'cvu';
import { twMerge } from 'tailwind-merge';
const buttonVariants = cvu(
['your', 'base', 'classes'],
{
variants: {
intent: {
primary: ['your', 'primary', 'classes'],
},
},
defaultVariants: {
intent: 'primary',
},
},
);
export const buttonClassNames = (props: VariantProps<typeof buttonVariants>) => {
return twMerge(buttonVariants(props));
};
Here is a simple example of a cvu
generated utility function for generating class names for a button component.
Note
The use of Tailwind CSS here is purely for demonstration purposes.
cvu
is not tied to any specific CSS framework.
import { cvu } from 'cvu';
const buttonClassnames = cvu(
['font-semibold', 'border', 'rounded'],
// --or--
// 'font-semibold border rounded'
{
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: {
sm: 'text-sm py-1 px-2',
md: ['text-base', 'py-2', 'px-4'],
},
},
compoundVariants: [
{
intent: 'primary',
size: 'md',
className: 'uppercase',
},
],
defaultVariants: {
intent: 'primary',
size: 'md',
},
},
);
buttonClassnames();
// => 'font-semibold border rounded bg-blue-500 text-white border-transparent hover:bg-blue-600 text-base py-2 px-4 uppercase'
buttonClassnames({ intent: 'secondary', size: 'sm' });
// => 'font-semibold border rounded bg-white text-gray-800 border-gray-400 hover:bg-gray-100 text-sm py-1 px-2'
Variants that apply when multiple other variant conditions are met.
import { cvu } from 'cvu';
const buttonClassnames = cva('…', {
variants: {
intent: {
primary: '…',
secondary: '…',
},
size: {
sm: '…',
md: '…',
},
},
compoundVariants: [
// Applied via
// `buttonClassnames({ intent: 'primary', size: 'md' });`
{
intent: 'primary',
size: 'md',
// This is the className that will be applied.
className: '…',
},
],
});
import { cvu } from 'cvu';
const buttonClassnames = cva('…', {
variants: {
intent: {
primary: '…',
secondary: '…',
},
size: {
sm: '…',
md: '…',
},
},
compoundVariants: [
// Applied via
// `buttonClassnames({ intent: 'primary', size: 'md' });`
// or
// `buttonClassnames({ intent: 'secondary', size: 'md' });`
{
intent: ['primary', 'secondary'],
size: 'md',
// This is the className that will be applied.
className: '…',
},
],
});
All cvu
utilities provide an optional string argument, which will be appended to the end of the generated class name.
This is useful in cases where want to pass a React className
prop to be merged with the generated class name.
import { cvu } from 'cvu';
const buttonClassnames = cvu('rounded', {
variants: {
intent: {
primary: 'bg-blue-500',
},
},
});
buttonClassnames(undefined, 'm-4');
// => 'rounded m-4'
buttonClassnames({ intent: 'primary' }, 'm-4');
// => 'rounded bg-blue-500 m-4'
VariantProps
cvu
offers the VariantProps
helper to extract variant types from a cvu
utility.
import { cvu, type VariantProps } from 'cvu';
type ButtonClassnamesProps = VariantProps<typeof buttonClassnames>;
const buttonClassnames = cvu(/* … */);
VariantPropsWithRequired
Additionally, cvu
offers the VariantPropsWithRequired
helper to extract variant types from a cvu
utility, with the specified keys marked as required.
import { cvu, type VariantPropsWithRequired } from 'cvu';
type ButtonClassnamesProps = VariantPropsWithRequired<typeof buttonClassnames, 'intent'>;
const buttonClassnames = cvu('…', {
variants: {
intent: {
primary: '…',
secondary: '…',
},
size: {
sm: '…',
md: '…',
},
},
});
const wrapper = (props: ButtonClassnamesProps) => {
return buttonClassnames(props);
};
// ❌ TypeScript Error:
// Argument of type "{}": is not assignable to parameter of type "ButtonClassnamesProps".
// Property "intent" is missing in type "{}" but required in type
// "ButtonClassnamesProps".
wrapper({});
// ✅
wrapper({ intent: 'primary' });
import { cvu, cx, type VariantProps } from "cvu";
/**
* Box
*/
export type BoxClassnamesProps = VariantProps<typeof boxClassnames>;
export const boxClassnames = cvu(/* … */);
/**
* Card
*/
type CardBaseClassNamesProps = VariantProps<typeof cardBaseClassnames>;
const cardBaseClassnames = cvu(/* … */);
export interface CardClassnamesProps extends BoxClassnamesProps, CardBaseClassnamesProps {}
export const cardClassnames = ({ /* destructured props */ }: CardClassnamesProps = {}) =>
cx(boxClassnames({ /* … */ }), cardBaseClassnames({ /* … */ }));
cvu
Builds a typed utility function for constructing className strings with given variants.
import { cvu } from 'cvu';
const classVariants = cvu('base', variantsConfig);
base
- the base class name (string
, string[]
, or other clsx
compatible value).variantsConfig
- (optional)
variants
- your variants schema
componentVariants
- variants based on a combination of previously defined variants
defaultVariants
- set default values for previously defined variants.
Note: these default values can be removed completely by setting the variant as null
.
For pioneering the variants
API movement.
For the inspiration behind cvu
. I personally didn't find the library to quite meet my needs or API preferences, but it's a great library nonetheless.
An amazing library for lightweight utility for constructing className strings conditionally.
FAQs
A tiny, performant, utility for constructing variant based CSS class strings.
The npm package cvu receives a total of 10 weekly downloads. As such, cvu popularity was classified as not popular.
We found that cvu demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.