Паттерны
Строка статуса
Когда использовать:
- одно действие выполняется, и текст рядом может это объяснить
Заметки по композиции:
- сочетайте спиннер с коротким текстом статуса
- используйте небольшой размер
Компромиссы:
- компактно и понятно
- смысл зависит от текста рядом
import { Spinner, Text } from '@vega-ui/react';
import { useId } from 'react';
export default function InlineStatusRow() {
const labelId = useId();
return (
<div style={{ display: 'flex', gap: 'var(--spacing-4)', alignItems: 'center' }}>
<Spinner size={2} aria-labelledby={labelId} />
<Text id={labelId} size={2}>Syncing 128 contacts from Google</Text>
</div>
);Загрузчик по центру поверхности
Когда использовать:
- панель или секция загружается, а содержимое ещё не готово
Заметки по композиции:
- размещайте спиннер по центру зарезервированной области
- выбирайте размер больше, чем при встроенном использовании
Компромиссы:
- легко заметить
- на время загрузки скрывает детали содержимого
import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogTrigger,
Heading,
Icon,
IconButton,
Spinner,
Text,
} from '@vega-ui/react';Кнопка в состоянии ожидания
Когда использовать:
- действие выполняется, и кнопка временно отключена
Заметки по композиции:
- делайте спиннер компактным
- отключайте кнопку на время ожидания
Компромиссы:
- понятная мгновенная обратная связь
- если текст полностью исчезает, контекст может ослабнуть
import { Button, HelperText, Label, Spinner, TextField, TextFieldInput } from '@vega-ui/react';
import { CSSProperties, FormEvent, useId, useState } from 'react';
export default function ButtonPendingState() {
const fieldId = useId();
const [pending, setPending] = useState(false);
const [message, setMessage] = useState('');
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
const workspace = String(data.get('workspace'));Сравнение
Быстрое правило выбора
Используйте Spinner, когда временному состоянию ожидания нужен компактный анимированный индикатор. Не используйте его вместо сохранения раскладки или показа итогового статуса.
Spinner или сохранённое содержимое
Используйте Spinner, когда:
- ожидание короткое, а действие и так понятно
Оставляйте содержимое на месте, когда:
- сохранение раскладки важнее движения
Spinner или индикаторы прогресса
Используйте Spinner, когда:
- точный прогресс неизвестен
Используйте Progress, когда:
- прогресс можно измерить
Выбирайте этот компонент, когда
- загрузка имеет неопределённую длительность
- достаточно компактного индикатора
- интерфейсу не нужно показывать степень завершения числом или полосой
Не выбирайте этот компонент, когда
- точный прогресс известен
- интерфейсу нужно больше контекста, чем может дать маленькое анимированное кольцо
Решение проблем
Пользователи не понимают, что загружается
Симптом
Спиннер виден, но пользователи не знают, какая операция выполняется.
Вероятная причина
Спиннер отрендерен без поясняющего текста или окружающей структуры.
Как проверить
- посмотрите на интерфейс, не зная деталей реализации
- проверьте, понятна ли выполняемая операция из содержимого рядом
Решение
Сочетайте спиннер с текстом статуса или размещайте его внутри поверхности, состояние ожидания которой однозначно.
Спиннер кажется слишком большим или слишком маленьким
Симптом
Индикатор загрузки визуально не сбалансирован в своём контейнере.
Вероятная причина
Числовой size не соответствует окружающему контролу или поверхности.
Как проверить
- сравните текущий размер с соседним текстом и контролами
Решение
Используйте меньшие размеры в строке и в кнопках, а большие — для загрузчиков по центру секций.
О загрузке сообщает только движение
Симптом
Пользователи, которые не замечают движения или не могут на него полагаться, не получают достаточно информации о статусе.
Вероятная причина
Спиннер — единственный сигнал состояния ожидания.
Как проверить
- мысленно уберите движение и проверьте, остаётся ли какой-нибудь текст статуса
Решение
Для значимых асинхронных операций добавьте текст статуса рядом или live-регион уровнем выше.