Vanilla Extract — это CSS-in-JS библиотека для создания типобезопасных, масштабируемых стилей в приложениях на JavaScript и TypeScript. В сочетании с Radix UI она позволяет аккуратно разделять логику компонентов и оформление, сохраняя строгую типизацию и поддержку темизации.
Radix UI предоставляет примитивные компоненты с полностью контролируемым стилевым слоем. Использование Vanilla Extract делает процесс стилизации этих компонентов прозрачным и удобным, обеспечивая совместимость с CSS-переменными и модульной архитектурой.
Для работы с Vanilla Extract необходимо установить пакет:
npm install @vanilla-extract/css
Для TypeScript проектов также требуется подключить типы:
npm install --save-dev @types/node
Конфигурация сборщика (Vite, Webpack) должна поддерживать
vanilla-extract:
@vanilla-extract/vite-plugin.@vanilla-extract/webpack-plugin вместе с
css-loader.Пример для Vite:
import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
export default {
plugins: [vanillaExtractPlugin()],
};
Vanilla Extract использует style и
recipe для определения базовых и
динамических стилей.
import { style, recipe } from '@vanilla-extract/css';
export const button = style({
padding: '10px 20px',
borderRadius: '4px',
fontWeight: 'bold',
cursor: 'pointer',
});
export const buttonVariants = recipe({
base: button,
variants: {
color: {
primary: { backgroundColor: 'blue', color: 'white' },
secondary: { backgroundColor: 'gray', color: 'black' },
},
size: {
small: { fontSize: '12px', padding: '6px 12px' },
large: { fontSize: '18px', padding: '12px 24px' },
},
},
defaultVariants: {
color: 'primary',
size: 'small',
},
});
Ключевые моменты:
style — создание простого класса с фиксированными
стилями.recipe — создание вариативного класса с возможностью
динамически менять стили через пропсы.defaultVariants — определяет базовые варианты для
компонента.Radix UI предоставляет примитивы без собственных стилей
(unstyled primitives). Vanilla Extract идеально подходит
для их стилизации.
Пример кнопки с Radix UI Button:
import * as RadixButton from '@radix-ui/react-button';
import { buttonVariants } from './styles.css';
export const MyButton = ({ color, size, ...props }) => {
return (
<RadixButton.Root className={buttonVariants({ color, size })} {...props}>
{props.children}
</RadixButton.Root>
);
};
Особенности:
disabled или
active, через дополнительные variants.Vanilla Extract поддерживает CSS-переменные, что позволяет создавать темы.
import { createTheme, style } from '@vanilla-extract/css';
export const lightTheme = createTheme({
color: {
background: 'white',
text: 'black',
primary: 'blue',
},
});
export const darkTheme = createTheme({
color: {
background: '#1a1a1a',
text: 'white',
primary: 'purple',
},
});
export const card = style({
backgroundColor: 'var(--color-background)',
color: 'var(--color-text)',
padding: '16px',
borderRadius: '8px',
});
Использование темы с Radix UI:
import { darkTheme, card } from './themes.css';
export const DarkCard = () => {
return (
<div className={darkTheme}>
<div className={card}>Темная карточка</div>
</div>
);
};
Vanilla Extract позволяет описывать состояния через selectors и variants:
export const toggleButton = recipe({
base: {
padding: '10px',
borderRadius: '4px',
border: '1px solid gray',
cursor: 'pointer',
selectors: {
'&:hover': {
backgroundColor: 'lightgray',
},
},
},
variants: {
active: {
true: { backgroundColor: 'blue', color: 'white' },
false: { backgroundColor: 'white', color: 'black' },
},
},
});
Интеграция с Radix UI Toggle:
import * as RadixToggle from '@radix-ui/react-toggle';
import { toggleButton } from './styles.css';
export const MyToggle = ({ active, ...props }) => {
return (
<RadixToggle.Root className={toggleButton({ active })} {...props}>
{props.children}
</RadixToggle.Root>
);
};
recipe для компонентов с несколькими
вариантами стиля.Vanilla Extract с Radix UI создаёт мощный стек для современных приложений: строго типизированные, стилизуемые, доступные компоненты, которые легко поддерживать и расширять.