Atomic Design на практике в React: как строить UI без хаоса

Практический разбор Atomic Design в React: atoms, molecules, organisms, шаблоны, страницы, типичные ошибки, производительность и ответы для интервью.

24 марта 2026 г.18 минLexicon Team

Введение

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

Классическая модель включает пять уровней:

  1. atoms
  2. molecules
  3. organisms
  4. templates
  5. pages

Смысл уровней не в размере файла и не в количестве строк. Важна роль в композиции.

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 собирает конкретный экран и подставляет реальные значения.

Поток данных и ответственности

Рабочий поток обычно выглядит так:

  1. BillingPage получает данные и обработчики из page-level хука или feature-модуля.
  2. AccountLayout раскладывает экран по зонам.
  3. BillingSummary и InvoicesTable как organisms показывают крупные блоки.
  4. Внутри organisms используются molecules вроде SectionHeader и StatItem.
  5. Базовые 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 или модульной архитектуре.

Как отвечать на интервью

Убедительный ответ обычно звучит так:

  1. Atomic Design это подход к проектированию UI, где интерфейс делят на уровни композиции: от примитивов до страниц.
  2. Его цель не в красоте папок, а в контроле ответственности компонентов и предсказуемом росте интерфейса.
  3. Atom это базовый UI-примитив, molecule маленький составной паттерн, organism крупный блок экрана, template каркас, page конкретный экран с данными.
  4. Подход особенно полезен там, где есть повторяющиеся формы, таблицы, панели и общая дизайн-система.
  5. Сам по себе 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

Читайте также