Содержание
Коротко
На Dev.to автор DashForge рассказывает, как проблема «форм в React» оказалась не CSS, а проводкой: Controller, watch, useEffect на каждое поле. Ответ — typed props вместо className-супа, мост к React Hook Form и компоненты, которые сами знают форму, видимость и права доступа.
Что произошло
Стартовая боль знакома: Tailwind решает cascade и мёртвые стили, но визуальная часть живёт в непрозрачной строке без автодополнения и рефакторинга. Автор спросил: что если variant, color, size — обычные типизированные props, а за кадром — utilities через tailwind-variants и design tokens?
Следующий слой — формы. Паттерн RHF с Controller и render prop на 50-м поле утомляет. TextField с name="email" сам читает value, ошибки и blur/submit-логику через context-мост — без ручной проводки.
Дальше — оркестрация бизнес-UI:
- visibleWhen — поле описывает условие показа (
customerType === business), безwatch+useEffectна каждое правило. - access на кнопке —
invoice:updateвнутри компонента, а неpermissions.includesв каждом экране.
Архитектурный поворот: две UI-библиотеки (MUI и Tailwind + Radix) с одинаковыми props оркестрации, но общим headless-движком (мост форм, видимость полей, RBAC). Стили сменяемы; «интеллект» приложения — в ядре.
Почему это важно
В enterprise-формах основная стоимость — не пиксели, а glue-код: связать поле с формой, валидацией, правами, условной видимостью. Typed visual API снижает класс ошибок в стилях; application-aware components — повторяющийся boilerplate на сотнях экранов.
Это не «ещё один UI-kit»: DashForge в alpha, но идея — вынести повторяющуюся оркестрацию в декларативные props, оставив Radix/React Aria для a11y.
На практике
- Visual API — props-first поверх Tailwind; один escape hatch
sxс tailwind-merge. - Поля —
<TextField name="…" label="…" />вместоController+ error plumbing. - Условия —
visibleWhen={{ field, equals }}вместо watch/effect. - Права —
access="resource:action"на интерактивных узлах. - Оценка зрелости — alpha; смотреть
@dashforge/twи repo перед adoption в продакшен.
| Было | Стало |
|---|---|
| className-строка | typed variant/color/size |
| Controller × N | context bridge |
| watch + effect × правила | visibleWhen |
| permissions && в JSX | access на Button |
Итог
История — про смещение фокуса с «как стилизовать» на «как компонент участвует в приложении». Если устали от copy-paste проводки форм — имеет смысл посмотреть DashForge как эксперимент, не как готовую замену всему стеку.