Custom Rules
The plugin can be extended through rules and defineRule.
import { defineConfig } from 'vite'
import { defineRule, isColorValue, isSizeValue, utilsJIT } from '@vueland/utils-jit'
export default defineConfig({
plugins: [
utilsJIT({
rules: [
defineRule({
name: 'surface',
matcher: /^surface-\[(.+)\]$/,
validate: isColorValue,
declaration: (value) => ({
backgroundColor: value,
}),
important: false,
}),
defineRule({
name: 'size',
matcher: /^size-\[(.+)\]$/,
validate: isSizeValue,
declaration: (value) => ({
width: value,
height: value,
}),
}),
defineRule({
name: 'flex-center',
matcher: /^flex-center$/,
declaration: () => ({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}),
}),
defineRule({
name: 'grid-cols',
matcher: /^grid-cols-(\d+)$/,
validate: (value) => Number(value) > 0,
declaration: (value) => ({
display: 'grid',
gridTemplateColumns: `repeat(${value}, minmax(0, 1fr))`,
}),
}),
],
}),
],
})Use the generated utilities anywhere your framework accepts class strings:
<div class="surface-[#fff] size-[40px] hover:size-[48px] flex-center grid-cols-3">
Custom utilities
</div>Generated CSS:
.surface-\[\#fff\] {
background-color: #fff;
}
.size-\[40px\] {
width: 40px !important;
height: 40px !important;
}
.hover\:size-\[48px\]:hover {
width: 48px !important;
height: 48px !important;
}
.flex-center {
display: flex !important;
justify-content: center !important;
align-items: center !important;
}
.grid-cols-3 {
display: grid !important;
grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
}defineRule API
defineRule({
name: 'rule-name',
matcher: /^rule-name-(.+)$/,
validate: (value) => true,
declaration: (value) => ({
cssProperty: value,
}),
important: true,
})namestringmatcherRegExpvalidate(value: string, match: RegExpMatchArray) => booleandeclaration(value: string, match: RegExpMatchArray) => Record<string, string | number> | string[]importantboolean!important to object-based declarations. Defaults to true.matcher receives only the utility part without variants. If the matcher has a capture group, value is the first captured group. If there is no capture group, value is the utility itself. Before validate and declaration run, the resolved value is normalized and checked by the internal CSS value safety guard.
For this class:
<div class="hover:surface-[#fff]"></div>matcher should match:
surface-[#fff]For a static class, match the utility directly:
defineRule({
name: 'flex-center',
matcher: /^flex-center$/,
declaration: () => ({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}),
})For parameterized classes without [], use capture groups:
defineRule({
name: 'grid-cols',
matcher: /^grid-cols-(\d+)$/,
validate: (value) => Number(value) > 0,
declaration: (value) => ({
gridTemplateColumns: `repeat(${value}, minmax(0, 1fr))`,
}),
})Declarations
declaration usually returns an object with CSS properties:
defineRule({
name: 'bg',
matcher: /^bg-\[(.+)\]$/,
validate: isColorValue,
declaration: (value) => ({
backgroundColor: value,
}),
})CSS properties written in camelCase are automatically converted to kebab-case:
{
backgroundColor: '#fff',
borderTopLeftRadius: '8px',
}Result:
background-color: #fff !important;
border-top-left-radius: 8px !important;CSS variables are preserved:
defineRule({
name: 'token',
matcher: /^token-\[(.+)\]$/,
declaration: (value) => ({
'--vl-token': value,
}),
important: false,
})Result:
--vl-token: #fff;If declaration returns string[], the strings are treated as final CSS declarations. In this case, !important is not added automatically.
defineRule({
name: 'raw',
matcher: /^raw-\[(.+)\]$/,
declaration: (value) => [`--raw-value: ${value};`],
})Stricter validation
For custom rules, it is better to explicitly restrict the allowed value format:
import { defineRule } from '@vueland/utils-jit'
const gridColsRule = defineRule({
name: 'grid-cols',
matcher: /^grid-cols-(\d+)$/,
validate: (value) => /^\d+$/.test(value),
declaration: (value) => ({
gridTemplateColumns: `repeat(${value}, minmax(0, 1fr))`,
}),
})Usage:
<div class="grid-cols-3"></div>Result:
.grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
}Validators
The package exports validators that can be used in custom rules:
import {
isColorValue,
isMarginValue,
isOpacityValue,
isPaddingValue,
isPositionValue,
isRadiusValue,
isSizeValue,
isZIndexValue,
} from '@vueland/utils-jit'Example:
defineRule({
name: 'text',
matcher: /^text-\[(.+)\]$/,
validate: isColorValue,
declaration: (value) => ({
color: value,
}),
})