Статусы и badges

В интерфейсах современных веб-приложений требуется быстро передавать пользователю состояние объекта, процесса или сущности. Для этой цели применяются статусы и badges — компактные визуальные индикаторы, которые позволяют:

  • показать текущее состояние данных
  • выделить важную информацию
  • сигнализировать о действиях пользователя
  • отображать количество элементов или уведомлений
  • структурировать интерфейс

Типичные примеры использования:

  • статус заказа: Processing, Shipped, Delivered
  • состояние задачи: Open, In Progress, Done
  • индикатор уведомлений: 3
  • метка категории: New, Beta
  • индикатор активности: Online, Offline

Библиотека Radix UI не предоставляет готового компонента Badge, однако предлагает низкоуровневые primitives, из которых удобно строить систему статусов и меток. Такой подход соответствует философии библиотеки — предоставить поведенческие и доступные primitives, а внешний вид и композицию оставить разработчику.


Концепция primitives в Radix UI

Radix UI строится вокруг идеи headless-компонентов. Это означает, что библиотека:

  • реализует логику поведения
  • обеспечивает доступность (accessibility)
  • не навязывает визуальный стиль

Badge или статус можно построить на основе следующих primitives:

  • Slot
  • AccessibleIcon
  • Tooltip
  • HoverCard
  • VisuallyHidden
  • Presence

Такая архитектура позволяет создавать:

  • простые текстовые badges
  • статусные индикаторы с иконками
  • интерактивные badges
  • badges с всплывающими подсказками
  • индикаторы состояния в реальном времени

Простая реализация Badge

Badge — компактная метка, обычно содержащая текст или число.

Базовый компонент

function Badge({ children, variant = "default" }) {
  return (
    <span className={`badge badge-${variant}`}>
      {children}
    </span>
  );
}

Использование

<Badge>New</Badge>
<Badge variant="success">Active</Badge>
<Badge variant="warning">Pending</Badge>

Возможные варианты

Вариант Значение
default обычная метка
success успешное состояние
warning предупреждение
danger ошибка
info информационный статус

Система цветовых статусов

Для удобства проектируется единая система цветовых состояний.

Пример CSS

.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 9999px;
  font-size: 12px;
  font-weight: 500;
}

.badge-default {
  background: #f1f1f1;
  color: #333;
}

.badge-success {
  background: #e6f7ec;
  color: #1a7f37;
}

.badge-warning {
  background: #fff4e5;
  color: #9a6700;
}

.badge-danger {
  background: #fdecea;
  color: #b42318;
}

Badge с иконкой

Метки часто сопровождаются иконками, чтобы быстрее передавать смысл статуса.

Radix UI предоставляет primitive AccessibleIcon, позволяющий корректно описывать иконки для скринридеров.

Пример

import { AccessibleIcon } from "@radix-ui/react-accessible-icon";
import { CheckIcon } from "@radix-ui/react-icons";

function StatusBadge() {
  return (
    <span className="badge badge-success">
      <AccessibleIcon label="Success">
        <CheckIcon />
      </AccessibleIcon>
      Active
    </span>
  );
}

Преимущество:

  • иконка получает текстовое описание
  • screen reader корректно интерпретирует элемент

Числовые badges (notification badges)

Часто badge используется для отображения количества уведомлений.

Компонент

function NotificationBadge({ count }) {
  return (
    <span className="notification-badge">
      {count > 99 ? "99+" : count}
    </span>
  );
}

Использование

<button className="notification-button">
  Messages
  <NotificationBadge count={5} />
</button>

CSS

.notification-button {
  position: relative;
}

.notification-badge {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 18px;
  height: 18px;
  border-radius: 999px;
  background: red;
  color: white;
  font-size: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
}

Статусные индикаторы

Иногда требуется не текстовая метка, а точечный индикатор состояния.

Пример

function StatusDot({ status }) {
  return (
    <span className={`status-dot status-${status}`} />
  );
}

CSS

.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.status-online {
  background: #22c55e;
}

.status-offline {
  background: #9ca3af;
}

.status-busy {
  background: #ef4444;
}

Badge с Tooltip (Radix UI)

Иногда необходимо пояснить статус. Для этого используется Tooltip primitive.

Установка

npm install @radix-ui/react-tooltip

Пример

import * as Tooltip from "@radix-ui/react-tooltip";

function StatusWithTooltip() {
  return (
    <Tooltip.Provider>
      <Tooltip.Root>
        <Tooltip.Trigger asChild>
          <span className="badge badge-warning">
            Pending
          </span>
        </Tooltip.Trigger>

        <Tooltip.Portal>
          <Tooltip.Content className="tooltip">
            Awaiting approval
          </Tooltip.Content>
        </Tooltip.Portal>
      </Tooltip.Root>
    </Tooltip.Provider>
  );
}

Преимущества:

  • доступность
  • управление фокусом
  • корректная работа клавиатуры
  • порталы для overlay

Badge внутри компонентов интерфейса

Badges используются внутри различных элементов интерфейса.

Tabs

<Tab>
  Messages
  <Badge>3</Badge>
</Tab>
<MenuItem>
  Updates
  <Badge variant="info">New</Badge>
</MenuItem>

Card

<Card>
  <Badge variant="success">Published</Badge>
</Card>

HoverCard для расширенного статуса

Если статус требует дополнительной информации, используется HoverCard.

Пример

import * as HoverCard from "@radix-ui/react-hover-card";

function StatusHoverCard() {
  return (
    <HoverCard.Root>
      <HoverCard.Trigger asChild>
        <span className="badge badge-info">
          Build
        </span>
      </HoverCard.Trigger>

      <HoverCard.Content className="hover-card">
        Build completed successfully.
      </HoverCard.Content>
    </HoverCard.Root>
  );
}

Анимированные статусы

Иногда статус должен сигнализировать об активном процессе.

Пример

.status-loading {
  background: #3b82f6;
  animation: pulse 1.5s infinite;
}

@keyframes pulse {
  0% {
    opacity: 0.4;
  }
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0.4;
  }
}

Использование

<Badge className="status-loading">
  Loading
</Badge>

Доступность статусов

Статусы должны быть доступны для пользователей с ограниченными возможностями.

Основные правила:

1. Использование ARIA

<span role="status">
  Processing
</span>

2. Использование VisuallyHidden

Radix предоставляет primitive для скрытого текста.

import { VisuallyHidden } from "@radix-ui/react-visually-hidden";

<span className="status-dot status-online">
  <VisuallyHidden>User is online</VisuallyHidden>
</span>

3. Не использовать только цвет

Плохая практика:

зелёный = успех
красный = ошибка

Правильный подход:

иконка + текст + цвет

Композиция Badge через Slot

Radix UI предоставляет primitive Slot, позволяющий переиспользовать компоненты.

Пример

import { Slot } from "@radix-ui/react-slot";

function Badge({ asChild, ...props }) {
  const Comp = asChild ? Slot : "span";

  return <Comp className="badge" {...props} />;
}

Использование

<Badge>Default</Badge>

<Badge asChild>
  <a href="/notifications">3</a>
</Badge>

Преимущества:

  • гибкость
  • интеграция с другими компонентами
  • переиспользование логики

Архитектура системы статусов

В крупных приложениях формируется централизованная система статусов.

Константы

export const STATUS = {
  ACTIVE: "active",
  PENDING: "pending",
  ERROR: "error",
  DISABLED: "disabled"
};

Маппинг цветов

const STATUS_VARIANTS = {
  active: "success",
  pending: "warning",
  error: "danger",
  disabled: "default"
};

Компонент

function StatusBadge({ status }) {
  const variant = STATUS_VARIANTS[status];

  return (
    <Badge variant={variant}>
      {status}
    </Badge>
  );
}

Производительность

Badges используются часто, поэтому важно учитывать оптимизацию.

Основные рекомендации

  • избегать лишних ререндеров
  • использовать memo
const Badge = React.memo(function Badge({ children }) {
  return <span className="badge">{children}</span>;
});
  • минимизировать сложную логику внутри компонента
  • использовать CSS вместо JS-анимаций

Использование в дизайн-системах

Badges являются частью большинства дизайн-систем:

  • Material Design
  • Atlassian Design System
  • Shopify Polaris
  • GitHub Primer

В типичной дизайн-системе badges обладают:

  • фиксированной высотой
  • предсказуемыми вариантами
  • единым цветовым токеном
  • адаптивным поведением

Типичные паттерны использования

1. Feature flags

Beta
Alpha
Experimental

2. Категории контента

News
Article
Tutorial

3. Статусы задач

Todo
In progress
Done

4. Метки версии

v1.2
Deprecated
Legacy

Ошибки проектирования badges

Слишком много вариантов

Плохая практика:

20 типов badges

Оптимально:

5–7 вариантов

Слишком длинный текст

Плохо:

This feature is currently under internal development

Хорошо:

Internal

Непоследовательность цветов

Если success зелёный в одном месте, он должен быть зелёным во всей системе.


Перегрузка интерфейса

Избыточное количество badges снижает их ценность.

Правило:

badge = сигнал важной информации

Практика проектирования

Хорошая система badges должна обеспечивать:

  • предсказуемость
  • единый стиль
  • доступность
  • масштабируемость
  • лёгкость интеграции

Radix UI благодаря headless primitives позволяет реализовать такую систему максимально гибко, комбинируя primitives и собственные стили, создавая как простые метки, так и сложные статусные индикаторы, интегрированные в архитектуру современного интерфейса.