Тема Tailwind CSS из дизайн‑токенов одной командой
- пятница, 30 октября 2026 г. в 00:00:13
Я сам рисую интерфейсы и сам их верстаю. У меня есть библиотека стилей pbstyles: цвета, размеры и шрифты в ней описаны дизайн‑токенами. Тему для Tailwind я хотел собирать из этих токенов, а не переписывать руками после каждой правки в Figma. Так появился пакет tailwind‑dictionary.
Он берёт токены в JSON и собирает из них тему Tailwind CSS. Светлая и тёмная тема собираются из тех же файлов.
Пакет пригодится, если у вас уже есть токены, но переходить на Tailwind не хочется из‑за того, что тему придётся вести отдельно. Или если вы уже на Tailwind и хотите выгружать переменные из Figma и сразу получать тему.
ИИ может забрать переменные из Figma и собрать тему. Но токены ИИ стоят денег, а тема пересобирается после каждой правки в макете. Тратить их на одну и ту же рутину жалко, лучше оставить на задачи посложнее. К тому же ИИ может каждый раз собрать тему чуть по‑разному.
С пакетом сборку настраиваешь один раз. Дальше это одна команда, и при тех же токенах тема всегда получается одинаковой.
Пакет читает токены в новом формате W3C Design Tokens (DTCG 2025.10) и в старом формате Style Dictionary. Подходит выгрузка из Figma, Tokens Studio и Terrazzo.
Собирает тему для Tailwind 4 и для Tailwind 3. Тем может быть сколько угодно: светлая, тёмная, контрастная, тема второго бренда. В тему попадают цвета, размеры, шрифты, текстовые стили, тени, брейкпоинты и анимации.
Вся настройка — один файл config.json. Редактор подсказывает его поля и подсвечивает ошибки. Есть режим --watch, который пересобирает тему при изменении токенов.
Figma выгружает переменные сама: в окне Variables правый клик по коллекции → Export modes. На каждый режим получается файл *.tokens.json.
Возьмём простой пример. Палитра и радиусы лежат в коллекции без режимов. Цвета primary, background и foreground лежат в коллекции с режимами Light и Dark и ссылаются на палитру.
Так выглядит палитра:
{ "color": { "blue": { "600": { "$type": "color", "$value": { "colorSpace": "srgb", "components": [0.149, 0.388, 0.922], "alpha": 1, "hex": "#2563EB" }, "$extensions": { "com.figma.variableId": "VariableID:1:3" } } } }, "radius": { "4": { "$type": "number", "$value": 4 } } }
А так режим Light:
{ "color": { "primary": { "$type": "color", "$value": "{color.blue.600}" } } }
В CSS это напрямую не вставишь. Цвет записан объектом, primary ссылается на другую переменную, а у радиуса нет единицы: --radius-4: 4 браузер не поймёт. Пакет всё это разбирает сам.
npm install --save-dev tailwind-dictionary
Палитру кладём в tokens/Primitives.tokens.json, режимы — в tokens/Light.tokens.json и tokens/Dark.tokens.json. Рядом создаём config.json:
{ "version": 4, "source": ["tokens/Primitives.tokens.json"], "themes": { "light": ["tokens/Light.tokens.json"], "dark": ["tokens/Dark.tokens.json"] }, "output": "./styles", "themeAliases": { "color": "color", "radius": "radius", "spacing": "1px" } }
В source лежат токены, общие для всех тем, в themes — файлы тем. В themeAliases слева ключ темы Tailwind, справа группа токенов. Если в Figma радиусы называются rounded, пишем "radius": "rounded". Строка "spacing": "1px" задаёт шаг отступов: класс p-16 даст ровно 16 пикселей, как в макете.
Запускаем сборку и подключаем результат после Tailwind:
npx tailwind-dictionary
@import 'tailwindcss'; @import './styles/tailwind/theme.css';
Теперь в проекте работают классы bg-primary, text-foreground и rounded-4.
Файл theme.css, светлая тема для краткости убрана:
:root { --theme-color-primary: #2563eb; --theme-color-background: #f9fafb; --theme-color-foreground: #111827; } [data-theme='dark'] { --theme-color-primary: #3380f5; --theme-color-background: #111827; --theme-color-foreground: #f9fafb; } @theme { --*: initial; --color-*: initial; --color-blue-400: #3380f5; --color-blue-600: #2563eb; --color-gray-50: #f9fafb; --color-gray-900: #111827; --radius-0: 0; --radius-4: 4px; --radius-8: 8px; --spacing: 1px; } @theme inline { --color-primary: var(--theme-color-primary); --color-background: var(--theme-color-background); --color-foreground: var(--theme-color-foreground); }
Цвета стали обычными hex, ссылки заменились значениями. Радиус 4 превратился в 4px. Единицу можно поменять опцией numberUnit: "rem" делит число на 16, false оставляет как есть.
Строка --*: initial убирает стандартную тему Tailwind. В проекте остаются только ваши значения, и случайный bg-blue-500, которого нет в макете, просто не соберётся.
Цвета тем лежат в --theme-color-*, а Tailwind ссылается на них через @theme inline. Благодаря inline класс bg-primary компилируется в background-color: var(--theme-color-primary), и значение берётся на том элементе, где стоит класс. Поэтому тему можно поменять в любом месте страницы:
<html data-theme="dark"> <body> <section data-theme="light">Светлый блок на тёмной странице</section> </body> </html>
Без атрибута светлая и тёмная тема следуют настройкам системы. Атрибут на <html> их перекрывает, это нужно для переключателя темы на сайте.
Описания переменных Figma не выгружает. Текстовых стилей и теней в выгрузке тоже нет: в Figma это стили, а не переменные. Я описываю их токенами вручную, и токен типографики h64 превращается в класс text-h64 сразу с размером, интервалом и начертанием.
Файлы тем нельзя класть в source. Если написать tokens/**/*.json, а темы лежат в tokens/themes/, одни и те же токены придут дважды.
Старый формат Style Dictionary пакет тоже читает, но смешивать его с новым в одной сборке нельзя.
Если что‑то не так, ошибка выводится одной строкой — с именем токена и файла:
✘ Token "color.text" (tokens/color.json) references {color.nope}, which is not defined
В плейграунде можно вставить свою выгрузку из Figma и сразу увидеть готовую тему и превью в светлой и тёмной теме. Всё считается в браузере, токены никуда не отправляются.
С Figma пакет сам не синхронизируется: выгрузку нужно сделать руками и положить в репозиторий. Компоненты он тоже не собирает, только тему. Если Tailwind в проекте нет, из тех же токенов можно собрать CSS‑переменные и миксины для LESS и SCSS соседним пакетом mixin‑dictionary.
Страница пакета · GitHub · npm · документация
Токены pbstyles — пример с двумя темами