Design System  /  Principles  /  States

States

Empty, Error, Loading, Success, 404, Permission, Offline. Восемь состояний, в которых интерфейс не показывает контент. Это не edge cases — это до 30% всех экранов в продукте. Их нужно проектировать так же тщательно, как happy path.

Состояния — это разговор. Пользователь столкнулся с тем, чего не ожидал. Наша задача — объяснить что произошло, почему, и что делать дальше. Не «Error 500», а «Что-то пошло не так на нашей стороне. Мы уже знаем».

Empty

Нет данных, нет результатов, пустой инбокс. Тёплый тон: объясняем почему пусто и даём один первый шаг. Не «0 records found» — а «Здесь будут ваши запросы. Создайте первый.»

Empty — первое использование

— раздел «Запросы», пользователь только что зарегистрировался

Здесь будут ваши запросы

Создайте первый запрос — спросите что-то у ваших данных, и Analyst найдёт ответ.

Empty — нет результатов поиска

— фильтр не дал совпадений

Ничего не нашлось по «отказы Q4»

Попробуйте упростить запрос или сбросить фильтры — возможно, период слишком узкий.

Анатомия Empty-состояния

1. ИконкаПростая lucide icon в квадрате secondary — контекст («это инбокс», «это поиск»). 56×56.
2. ЗаголовокЧто здесь будет, не что его нет. «Здесь будут запросы», не «Нет запросов».
3. Объяснение1–2 предложения. Почему пусто и что нужно сделать.
4. ActionОдин primary CTA + опционально secondary («посмотреть пример», «прочитать гайд»).

Error — три уровня

Ошибка может проявиться на трёх уровнях. Уровень определяет место и вес сообщения.

Inline — под полем

Когда ошибка относится к конкретному полю формы. Не дёргает остальной экран.

— валидация поля
Похоже, домен неполный. Попробуйте ivan@aist.tech.

Page-level — вместо контента

Когда не удалось загрузить страницу или её ключевую часть. Контент заменяется состоянием.

— ошибка загрузки списка продуктов

Не удалось загрузить список

Что-то пошло не так на нашей стороне. Мы уже знаем и разбираемся.

request id: 7f2e1a · 12:14:33

Toast — фоновое действие

Когда что-то сломалось при фоновом действии (autosave, синхронизация, отправка), но сам экран жив. Toast в нижнем правом, dismissable.

— autosave не прошёл
Не удалось сохранить
Изменения остались только у вас. Повторить

Уровни — когда какой

КонтекстУровеньГде
Поле формыInlineПод полем, красный текст + бордер.
Страница не загрузиласьPage-levelВместо контента, full-bleed.
Action в модалке/sheetInlineСверху модалки, banner-стиль.
Фоновое действиеToastBottom-right, auto-dismiss 8s или persistent.
Action юзера упалToastНапример удаление, sharing, отправка email.

Action — контекстный

Тип ошибкиAction
Сетевая (timeout, 5xx)«Попробовать ещё раз» — retry того же запроса.
Валидация (4xx от юзера)Объяснение что не так. Action — исправить, не retry.
Permission«Запросить доступ» или «Сменить аккаунт». Не retry.
Не найдено (404)«Вернуться» или «К списку». Retry бессмысленен.
Серверная критическая«Попробовать» + «Сообщить нам» с request id.

Loading

Skeleton для страниц и контентных блоков, spinner для кнопок и мелких операций. Skeleton показывает структуру будущего контента, spinner — просто «работаю».

Skeleton — страница, список

Контуры повторяют структуру финального контента. Shimmer-анимация даёт обратную связь «загружается».

— список с аватарками + 2 строки текста

Spinner — в кнопке

Когда юзер инициировал короткое действие — сохранение, отправка. Кнопка disabled, текст меняется на spinner + продолжение.

— нажали «Сохранить»
→ через 800ms …

Когда skeleton, когда spinner

Загрузка страницы целикомSkeleton всех ключевых блоков.
Список / таблицаSkeleton 4–6 строк.
Один блок виджетаSkeleton с нужной формой.
Кнопка / inline-actionSpinner внутри кнопки + disabled.
Микро-операция (<200ms)Не показываем ничего — моргание раздражает.
Долгая загрузка (>3s)Skeleton + поясняющий текст. См. ниже.

Skeleton-токены

Цвет base#EDEDF0
Цвет highlight#F5F5F7
Анимацияshimmer 1.4s linear infinite
Высота строки текста12 px (small) / 14 px (body)
Border-radius6 px / round для аватарок

Долгая загрузка (>3 секунд)

Если что-то грузится дольше 3 секунд — нужно объяснить. Молчаливый spinner на 5+ секунд читается как «зависло».

— загрузка крупного отчёта, прошло 3 секунды

Собираем отчёт

Это занимает чуть больше времени — объём за квартал.

Тайминг сообщений

ВремяЧто показываем
0–200 msНичего. Ответ должен прилететь сразу.
200 ms – 3 sSkeleton или spinner без текста.
3 s – 10 sSpinner + «Это занимает чуть больше времени …»
10 s+Прогресс-бар или этапы («Собираем данные… Считаем метрики…»).
30 s+Background job — отпустить юзера, прислать уведомление по завершении.

Success

Когда action завершился. Чаще всего — toast в углу, не page-level. Page-level success — только для крупных событий (оплата, регистрация, экспорт большого файла).

Success — toast

— продукт опубликован
Voice Operator опубликован
Доступен по ссылке aist.tech/voice

Success — page-level

— оплата прошла

Подписка активна

План «Team» — до 15 апреля 2026. Чек отправили на ivan@acme.ru.

404 — страница не найдена

Юзер прошёл по битой ссылке или удалённому объекту. Без «Sorry», без шуток про 404. Спокойно, по делу.

— /products/voice-operator/old-version
ERROR · 404

404

Этой страницы нет — возможно, её переименовали или удалили.

Permission denied

Объект существует, но у юзера нет прав. Не путать с 404. Объясняем почему нет доступа и даём путь его получить.

— member пытается зайти в «Биллинг»

Только для администраторов

Биллинг доступен пользователям с ролью «admin». Попросите Ивана Петрова дать доступ — он владелец организации.

Offline / нет сети

Сеть пропала. Не генерируем error page — показываем баннер сверху, держим интерфейс работоспособным насколько возможно. Возвращаем функциональность сразу, как сеть вернётся.

— верхний банер, sticky над topbar
Нет связи с сервером. Изменения сохраняются локально и синхронизируются автоматически.
Контент страницы остаётся доступным.

Что делаем при offline

Просмотр того что уже загруженоРаботает. Не блокируем.
Действия меняющие данныеКэшируем локально, синкаем при возврате связи.
Реал-тайм-фичи (чат, графики)Замораживаем, помечаем «не актуально».
При возврате связиBanner становится «Соединение восстановлено» green, потом исчезает через 3s.

Голос — тон сообщений

Человечный, без технических терминов и без извинений-преувеличений. Ответственность берём, не перекладываем на юзера.

Не такТак
Error 500: Internal Server Error Что-то пошло не так на нашей стороне. Мы уже знаем.
Sorry! Something went wrong :( Не удалось загрузить список. Попробуем ещё раз?
Failed to validate. Email is invalid. Похоже, домен неполный. Попробуйте ivan@aist.tech.
No data Здесь будут ваши запросы. Создайте первый.
You don't have permission Только для администраторов. Попросите Ивана дать доступ.
Unable to connect to server Нет связи с сервером. Изменения сохраняются локально.

Правила голоса

Принципы

DO

Empty показывает что будет и даёт первый шаг.

DON'T

Empty — просто текст «No data» в центре экрана.

DO

Skeleton повторяет финальный layout.

DON'T

Один большой spinner на всю страницу.

DO

Error содержит request-id для поддержки.

DON'T

«Something went wrong» — и всё.

DO

Долгая загрузка объясняет себя через 3 секунды.

DON'T

Spinner крутится 30 секунд молча.

DO

Success — чаще всего toast, не page.

DON'T

Полноэкранная success-страница после каждого save.

Tokens reference

StatePropertyValue
Empty iconsize / radius / bg56 × 14 / secondary
Error page iconsize / radius / bg64 × 16 / destructive @8%
Toastradius / shadow10 / 0 8 24 rgba(17,17,17,.06)
Toast widthmax380 px
Skeletonbase / highlight#EDEDF0 / #F5F5F7
Skeletonanimationshimmer 1.4s linear inf
Spinnersize / stroke16 × 2 / 24 × 2.5
Spinnerduration0.7s linear inf
404 numeralsize / weight64 / 800
Offline bannerbg / dot#1C1C1F / warning
Связанные: Density ·  Motion (skeleton + transitions) ·  Buttons (spinner в кнопках) ·  Badges (статусы)
Назад: ← Density ·  К хабу: Design System →