Atomic Design на практике в React: как строить UI без хаоса
Практический разбор Atomic Design в React: atoms, molecules, organisms, шаблоны, страницы, типичные ошибки, производительность и ответы для интервью.
- Введение
- Какую проблему решает Atomic Design в React
- Из каких уровней состоит Atomic Design
- Atoms
- Molecules
- Organisms
- Templates
- Pages
- Архитектурный разбор: как это выглядит в реальном React-проекте
- Контекст задачи
- Возможная схема компонентов
- Поток данных и ответственности
- Практика: как проектировать atoms, чтобы они не ломали продукт
- Практика: где проходит граница между molecule и organism
- Template и Page: уровень, который чаще всего пропускают зря
- Сравнение Atomic Design с другими подходами
- Production pitfalls
- 1. Atoms превращаются в набор бизнес-флагов
- 2. Organisms становятся "толстыми экранами"
- 3. Templates копируют верстку, но не уменьшают сложность
- 4. Команда спорит о названиях сильнее, чем о границах
- Разбор производительности
- Практики, которые делают Atomic Design рабочим
- Договоритесь о критериях уровней
- Не смешивайте UI-архитектуру и продуктовую архитектуру
- Проверяйте переиспользование задним числом, а не обещанием
- Держите API минималистичным
- Тестируйте уровни по роли
- Частые ошибки
- Как отвечать на интервью
- FAQ
- Atomic Design и дизайн-система это одно и то же?
- Можно ли использовать Atomic Design вместе с Feature-Sliced Design?
- Нужно ли выносить все формы в organisms?
- Почему команды часто разочаровываются в Atomic Design?
- Как понять, что Atomic Design уже помогает проекту?
- Итоги
Введение
Atomic Design в React часто воспринимают как красивую схему из пяти уровней: atoms, molecules, organisms, templates, pages. На практике польза появляется не от самих названий, а от дисциплины композиции компонентов. Подход помогает понять, какой компонент действительно является базовым примитивом, какой собирает пользовательский сценарий, а какой уже слишком знает о конкретной странице.
Проблема обычно начинается не в маленьком проекте, а когда UI растет быстрее, чем формируются договоренности команды. В репозитории появляются десятки ButtonPrimaryFinal, CardWrapper, UniversalInput, а папка components превращается в свалку решений без явных границ. Перед изучением Atomic Design полезно ознакомиться с архитектурой больших React-приложений: UI-слои не заменяют общую архитектуру, но сильно влияют на то, насколько предсказуемо растет интерфейс.
В этой статье разберем, как применять Atomic Design на практике в React, где проходит граница между уровнями, как не смешать UI-композицию с бизнес-логикой, когда подход реально помогает и как объяснить его на собеседовании без общих слов.
Больше вопросов в Telegram
Ежедневные разборы и реальные кейсы с интервью.
Какую проблему решает Atomic Design в React
Главная задача Atomic Design не в том, чтобы разложить компоненты по красивым папкам. Подход решает более приземленные проблемы:
- уменьшает хаос в UI-слое;
- помогает переиспользовать примитивы без копирования JSX;
- отделяет визуальные строительные блоки от экранной композиции;
- делает дизайн-систему и продуктовый код менее конфликтными;
- упрощает обсуждение границ компонента на code review.
Если без формальных терминов, то вопрос звучит так: этот компонент является переиспользуемым кирпичом интерфейса или это уже часть конкретного сценария? Пока команда не отвечает на него одинаково, любой каталог components очень быстро размывается.
Показательный симптом: один и тот же UserCard сначала используют как виджет профиля, потом как карточку участника, затем добавляют в него запросы, проверку ролей, аналитику кликов и условно отображаемый drawer. После этого компонент перестает быть UI-элементом и становится мини-приложением внутри себя. Atomic Design полезен именно тем, что помогает избежать неконтролируемого расширения ответственности.
Из каких уровней состоит Atomic Design
Классическая модель включает пять уровней:
atomsmoleculesorganismstemplatespages
Смысл уровней не в размере файла и не в количестве строк. Важна роль в композиции.
Atoms
Atom - это минимальный UI-примитив с предсказуемым поведением. Обычно сюда попадают Button, Input, Label, Icon, Badge, Spinner. Хороший atom не знает о форме регистрации, фильтрах каталога или валидации заказа. Он решает узкую задачу интерфейса и дает контролируемый API.
Molecules
Molecule собирает несколько atoms в маленький законченный паттерн. Например, поле формы из Label + Input + Hint + Error, поисковая строка, переключатель сортировки, карточка с заголовком и действием. У molecule уже есть смысл, но она все еще не должна знать о конкретной странице.
Organisms
Organism это крупный блок интерфейса, который собирает несколько molecules и atoms в заметную часть экрана: шапка страницы, форма профиля, таблица заказов с тулбаром, боковая панель фильтров. На этом уровне появляются состояния загрузки, пустого результата, переключение режимов и более сложная композиция.
Templates
Template описывает каркас страницы без привязки к конкретным данным. Это полезный уровень, когда продукт имеет несколько повторяющихся типов экранов: список, детальная страница, форма редактирования, кабинет с сайдбаром. Шаблон держит раскладку, зоны и общую композицию.
Pages
Page это конкретный экран с реальными данными, роутингом и привязкой к пользовательскому сценарию. Именно здесь template получает наполнение, а организмам передаются реальные props, derived state и обработчики. Если упростить: template отвечает за форму экрана, page за конкретный случай использования.
Архитектурный разбор: как это выглядит в реальном React-проекте
Контекст задачи
Представим личный кабинет SaaS-продукта. На странице биллинга есть текущий тариф, список счетов, форма смены карты, блок лимитов и боковая панель помощи. Если строить экран без явных границ, быстро появляется огромный BillingPage.tsx, который одновременно отвечает за layout, запросы, формы, валидацию и визуальные детали.
Atomic Design помогает разделить UI-композицию на слои, не смешивая ее с предметной логикой.
Возможная схема компонентов
src/
shared/ui/
atoms/
button/
input/
badge/
text/
molecules/
form-field/
section-header/
stat-item/
organisms/
billing-summary/
invoices-table/
payment-method-form/
templates/
account-layout/
pages/
billing/
ui/BillingPage.tsx
model/useBillingPage.ts
Здесь важно не то, что папки названы именно так. Важно, что:
Buttonне знает, что он кнопка "Сменить карту";FormFieldне знает про биллинг, но умеет отрисовать поле формы;PaymentMethodFormуже знает сценарий изменения платежного метода;AccountLayoutотвечает за сетку кабинета, а не за данные страницы;BillingPageсобирает конкретный экран и подставляет реальные значения.
Поток данных и ответственности
Рабочий поток обычно выглядит так:
BillingPageполучает данные и обработчики из page-level хука или feature-модуля.AccountLayoutраскладывает экран по зонам.BillingSummaryиInvoicesTableкак organisms показывают крупные блоки.- Внутри organisms используются molecules вроде
SectionHeaderиStatItem. - Базовые atoms отвечают только за низкоуровневый UI и единообразный API.
Из-за такого разбиения проще локализовать изменения. Если дизайнер меняет отступы и состояния кнопок, трогаются atoms и molecules. Если продукт меняет сценарий оплаты, правки чаще ограничиваются organism или page. Это и есть главный выигрыш: изменения становятся локальнее.
Практика: как проектировать atoms, чтобы они не ломали продукт
Самая частая ошибка при внедрении Atomic Design связана с atoms. Команда делает их "максимально универсальными", а через месяц получает десятки пропсов и веток поведения.
Тревожный признак выглядит так:
type ButtonProps = {
variant?: "primary" | "secondary" | "ghost" | "danger" | "marketing";
size?: "xs" | "sm" | "md" | "lg";
isLoading?: boolean;
isSuccess?: boolean;
withLeftIcon?: boolean;
withRightIcon?: boolean;
shouldStretchOnMobile?: boolean;
shouldAnimateOnHover?: boolean;
analyticsEvent?: string;
permission?: string;
};
Такой Button уже пытается быть и дизайн-системой, и бизнес-объектом, и местом для аналитики. На практике atom должен быть более узконаправленным.
Более рабочий вариант:
type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
variant?: "primary" | "secondary" | "ghost" | "danger";
size?: "sm" | "md" | "lg";
loading?: boolean;
};
export function Button({
variant = "primary",
size = "md",
loading = false,
children,
disabled,
...props
}: ButtonProps) {
return (
<button
data-variant={variant}
data-size={size}
disabled={disabled || loading}
{...props}
>
{loading ? "Загрузка..." : children}
</button>
);
}
Если кнопке нужна аналитика или проверка прав, это обычно ответственность более высокого уровня. Для такого случая лучше собрать отдельную molecule или organism, чем раздувать atom до "универсального центра всего".
Практика: где проходит граница между molecule и organism
Это место чаще всего вызывает проблемы при использовании Atomic Design в живых React-проектах. Хорошее рабочее правило:
- molecule реализует маленький повторяемый UI-паттерн;
- organism собирает законченный крупный фрагмент экрана.
Например, FormField с подписью, полем и ошибкой это molecule:
type FormFieldProps = {
label: string;
error?: string;
htmlFor: string;
} & React.InputHTMLAttributes<HTMLInputElement>;
export function FormField({
label,
error,
htmlFor,
...inputProps
}: FormFieldProps) {
return (
<label className="form-field" htmlFor={htmlFor}>
<span className="form-field__label">{label}</span>
<input id={htmlFor} className="form-field__input" {...inputProps} />
{error ? <span className="form-field__error">{error}</span> : null}
</label>
);
}
А PaymentMethodForm, который включает несколько полей, submit, состояние отправки и серверную ошибку, это уже organism:
type PaymentMethodFormProps = {
values: {
holder: string;
cardNumber: string;
};
errors: Partial<Record<"holder" | "cardNumber", string>>;
submitting: boolean;
submitError?: string;
onChange: (name: "holder" | "cardNumber", value: string) => void;
onSubmit: () => void;
};
export function PaymentMethodForm({
values,
errors,
submitting,
submitError,
onChange,
onSubmit,
}: PaymentMethodFormProps) {
return (
<section>
<h2>Платежный метод</h2>
<FormField
htmlFor="holder"
label="Имя владельца"
value={values.holder}
error={errors.holder}
onChange={(e) => onChange("holder", e.target.value)}
/>
<FormField
htmlFor="cardNumber"
label="Номер карты"
value={values.cardNumber}
error={errors.cardNumber}
onChange={(e) => onChange("cardNumber", e.target.value)}
/>
{submitError ? <p role="alert">{submitError}</p> : null}
<Button loading={submitting} onClick={onSubmit}>
Сохранить
</Button>
</section>
);
}
Если в проекте molecule начинает тянуть запросы, роутинг и доменные разрешения, она уже выросла в organism или вообще должна жить в feature-слое. Здесь Atomic Design полезно держать рядом с Feature-Sliced Design для React-проектов: первый отвечает за композицию UI, второй за место бизнес-логики и зависимостей продукта.
Template и Page: уровень, который чаще всего пропускают зря
Во многих командах Atomic Design обрывается на organisms. Это удобно на короткой дистанции, но потом крупные страницы начинают копировать одинаковую раскладку: заголовок, боковую колонку, фильтры, блок действий, основной контент.
Template полезен, когда:
- есть несколько однотипных экранов;
- раскладка повторяется, а данные разные;
- нужен единый ритм страницы без копирования layout-JSX.
Пример шаблона:
type AccountLayoutProps = {
title: string;
sidebar: React.ReactNode;
content: React.ReactNode;
};
export function AccountLayout({
title,
sidebar,
content,
}: AccountLayoutProps) {
return (
<div className="account-layout">
<header className="account-layout__header">
<h1>{title}</h1>
</header>
<aside className="account-layout__sidebar">{sidebar}</aside>
<main className="account-layout__content">{content}</main>
</div>
);
}
А page уже связывает его с реальным сценарием:
export function BillingPage() {
const billing = useBillingPage();
return (
<AccountLayout
title="Биллинг"
sidebar={<BillingHelp />}
content={
<>
<BillingSummary plan={billing.plan} />
<InvoicesTable invoices={billing.invoices} />
<PaymentMethodForm {...billing.paymentForm} />
</>
}
/>
);
}
Такое разделение уменьшает копипасту и делает страницу легче для чтения. Если в проекте уже болят повторяющиеся layout-решения, имеет смысл посмотреть и на compound components pattern в React: он хорошо сочетается с templates там, где нужно управляемое составление UI-блоков.
Сравнение Atomic Design с другими подходами
| Подход | Что упорядочивает | Сильная сторона | Ограничение | Когда уместен |
|---|---|---|---|---|
components/common/ui | Только хранение компонентов | Низкий порог входа | Почти нет правил роста | Небольшие проекты и прототипы |
| Atomic Design | Иерархию UI-композиции | Понятные уровни от примитивов до страниц | Не отвечает сам по себе за доменную логику | Продукты с повторяющимся интерфейсом и дизайн-системой |
| Feature folders | Пользовательские сценарии | Удобно группировать поведение | UI-примитивы часто размазываются | Приложения со сложными сценариями |
| Feature-Sliced Design | Слои продукта и зависимости | Сильные архитектурные границы | Требует дисциплины команды | Средние и большие React-продукты |
| Свободная композиция без правил | Локальные решения | Быстро на старте | Почти гарантированный хаос на масштабе | Одноразовые экраны и MVP |
Практический вывод простой: Atomic Design не конкурирует напрямую с архитектурой всего приложения. Он отвечает на вопрос "как устроить иерархию UI", а не "где должна жить бизнес-логика заказа". Поэтому в крупных проектах его чаще сочетают с более широкими подходами к модульности.
Production pitfalls
1. Atoms превращаются в набор бизнес-флагов
Симптомы:
- примитивы знают про роли, тарифы, аналитику и разрешения;
- у компонентов десятки пропсов с редко используемыми ветками;
- любое изменение атома ломает несколько независимых экранов.
Последствие: дизайн-система становится самым хрупким местом UI.
Как исправлять: возвращать atoms к роли визуального примитива, а различия, связанные со сценариями использовани, поднимать в molecules, organisms или feature-модули.
2. Organisms становятся "толстыми экранами"
Симптомы:
- organism содержит запросы, доменные вычисления, роутинг и побочные эффекты;
- компонент трудно протестировать отдельно от страницы;
- повторное использование оказывается мнимым, потому что организм жестко привязан к одному экрану.
Последствие: уровень organism перестает быть UI-композицией и начинает дублировать page.
Как исправлять: выносить загрузку данных и производные вычисления выше, а organism оставлять слоем представления и управляемого поведения.
3. Templates копируют верстку, но не уменьшают сложность
Такое случается, когда шаблон заводят ради термина, а не ради реальной повторяемости. Если template используется один раз и не несет правил композиции, он просто добавляет лишний файл.
Как проверять заранее: если без template экран не дублируется в коде и не усложняется, уровень можно не вводить.
4. Команда спорит о названиях сильнее, чем о границах
Это типичная проблема организации работы. Разработчики долго обсуждают, molecule это или organism, но не отвечают на более важный вопрос: можно ли менять этот блок локально и не сломать соседние сценарии.
Если спор не влияет на границы ответственности, он малоценен. Atomic Design должен экономить время команды, а не отнимать его.
Разбор производительности
Atomic Design не ускоряет React сам по себе. От того, что Button лежит в atoms, ререндеров меньше не станет. Но косвенное влияние на производительность у подхода есть.
Во-первых, он помогает не раздувать низкоуровневые компоненты лишней логикой. Чем чище atoms и molecules, тем проще контролировать их API, мемоизацию и стоимость повторного рендера. Это особенно полезно, когда вы уже ищете узкие места через React DevTools и профилирование или отдельный разбор поиска узких мест в React.
Во-вторых, через четкие уровни легче замечать, где композиция стала слишком дорогой:
- organism получает слишком много вычисляемых пропсов;
- template перерисовывает тяжелые зоны из-за локального флага;
- page прокидывает нестабильные колбэки через несколько уровней вниз;
- molecule выполняет тяжелые вычисления во время рендера.
Когда оптимизация оправдана:
- лаг воспроизводится в реальном сценарии пользователя;
- profiler показывает горячий путь;
- видно, какой уровень композиции создает лишнюю работу.
Когда оптимизация преждевременна:
- проблема ощущается только "на глаз";
- дерево маленькое и без тяжелых операций;
- основная задержка сидит в сети или layout, а не в React-композиции.
Если проект уже сталкивается с проблемой избыточных обновлений, полезно улучшить состояние продукта с помощью материалов про когда компонент действительно перерисовывается и memoization в React без мифов.
Прокачай React за 7 дней
20 вопросов и разборов по React Hooks.
Практики, которые делают Atomic Design рабочим
Договоритесь о критериях уровней
Команде нужен не плакат с пятью словами, а короткие правила. Например:
- atom не знает о продуктовой области;
- molecule решает маленький UI-паттерн;
- organism собирает крупный фрагмент интерфейса;
- template задает каркас повторяющегося экрана;
- page связывает UI с конкретными данными и маршрутом.
Не смешивайте UI-архитектуру и продуктовую архитектуру
Atomic Design плохо работает, когда им пытаются использовать как единственную архитектурную основу к проекту. UI-уровни не отвечают за кеширование, domain services, policy checks и orchestration пользовательского сценария. Для этого нужны отдельные границы.
Проверяйте переиспользование задним числом, а не обещанием
Не каждый блок обязан быть atom или molecule "на будущее". Если компонент используется один раз и не дает повторяемого паттерна, насильственное обобщение только ухудшит читаемость.
Держите API минималистичным
Чем длиннее список пропсов у atoms, тем быстрее дизайн-система начинает течь в разные стороны. Гораздо дешевле собрать новый molecule из простых деталей, чем превращать один базовый компонент в швейцарский нож.
Тестируйте уровни по роли
- atoms удобно тестировать как UI-примитивы и состояния;
- molecules как паттерны ввода и отображения ошибок;
- organisms как крупные пользовательские блоки;
- pages как интеграционные сценарии.
Так тесты лучше отражают реальную архитектуру интерфейса.
Частые ошибки
- Внедрять все пять уровней в маленький проект без повторяющихся экранов.
- Считать, что atom это просто "самый маленький компонент".
- Перегружать atoms сценарной логикой и аналитикой.
- Путать organism с page и складывать в него загрузку данных.
- Создавать templates без реальной повторяемости раскладки.
- Пытаться решить через Atomic Design проблемы, которые относятся к state management или модульной архитектуре.
Как отвечать на интервью
Убедительный ответ обычно звучит так:
Atomic Designэто подход к проектированию UI, где интерфейс делят на уровни композиции: от примитивов до страниц.- Его цель не в красоте папок, а в контроле ответственности компонентов и предсказуемом росте интерфейса.
Atomэто базовый UI-примитив,moleculeмаленький составной паттерн,organismкрупный блок экрана,templateкаркас,pageконкретный экран с данными.- Подход особенно полезен там, где есть повторяющиеся формы, таблицы, панели и общая дизайн-система.
- Сам по себе
Atomic Designне заменяет архитектуру продукта и не отвечает за бизнес-логику.
Если хотите показать уровень выше среднего, добавьте нюанс: Atomic Design полезен не в каждом проекте. Для простого кабинета на три страницы он может быть избыточен, а для большого интерфейса с богатой дизайн-системой заметно снижает хаос в UI-слое.
Еще один важный нюанс на интервью: объяснить, что вы оцениваете подход не по названиям уровней, а по стоимости изменений. Если изменение кнопки, формы или layout остается локальным, архитектура компонентов выбрана удачно.
Потренируйте React UI-архитектуру на реальных интервью-сценариях
Практика по React с разбором компонентных границ, Atomic Design, state management, производительности и архитектурных компромиссов в формате технического собеседования.
FAQ
Atomic Design и дизайн-система это одно и то же?
Нет. Дизайн-система включает токены, правила визуального языка, документацию, паттерны доступности и компоненты. Atomic Design это только один из способов упорядочить UI-композицию внутри этой системы.
Можно ли использовать Atomic Design вместе с Feature-Sliced Design?
Да. Это частая комбинация. Atomic Design описывает уровни UI, а Feature-Sliced Design помогает разложить продукт по слоям и зависимостям. Один подход не отменяет другой.
Нужно ли выносить все формы в organisms?
Не всегда. Если форма маленькая и используется как небольшой повторяемый паттерн, она может оставаться molecule. Важнее не название, а реальная сложность и зона ответственности.
Почему команды часто разочаровываются в Atomic Design?
Обычно не из-за самого подхода, а из-за формального внедрения. Когда уровни копируют механически, не договорившись о границах, структура становится бюрократией, а не инструментом.
Как понять, что Atomic Design уже помогает проекту?
По косвенным признакам: новые экраны собираются быстрее, базовые компоненты не обрастают сценарной логикой, правки в layout не размазываются по десяткам файлов, а обсуждения на review переходят от "куда положить" к "какая здесь ответственность".
Итоги
Atomic Design на практике полезен не как теоретическая модель, а как способ удержать порядок в UI-слое React-приложения. Он помогает отличать примитивы от паттернов, паттерны от крупных экранных блоков, а каркас страницы от ее конкретного сценария.
Лучше всего подход работает там, где интерфейс действительно повторяется: формы, кабинеты, таблицы, панели, шаблоны страниц, дизайн-система. В маленьком проекте он может быть лишним. В растущем продукте, где UI быстро усложняется, он часто помогает сэкономить время на поддержке и рефакторинге.
Хороший простой признак: команда может быстро объяснить, зачем существует каждый уровень и почему изменение остается локальным. Если это условие выполняется, Atomic Design в React используется не как модный термин, а как полезный инструмент.
Больше вопросов в Telegram
Ежедневные разборы и реальные кейсы с интервью.
Автор
Lexicon Team
Читайте также
frontend
Webpack vs Vite для React: что выбрать в 2026 году и как объяснить выбор на интервью
Сравниваем Webpack и Vite для React: dev server, HMR, production build, экосистема, производительность, типичные ошибки и сильный ответ для собеседования.
frontend
Как проектировать масштабируемый React frontend: архитектура, состояние и границы модулей
Практический разбор того, как проектировать масштабируемый React frontend: модули, state management, performance, типичные ошибки и сильный ответ на интервью.
frontend
System design для frontend разработчика: как мыслить системно, а не только компонентами
Практический разбор system design для frontend разработчика: границы ответственности, данные, производительность, ошибки и сильный ответ на интервью.