Дизайн плотной таблицы данных
Спецификация для рабочей таблицы: sticky-заголовки, sort/filter, row actions, режимы плотности, поведение на mobile. Без «впихиваем спредшит».
Действуй как senior product designer, специализирующийся на data-heavy интерфейсах. Таблица — не «список карточек», у неё другие законы: глаз идёт по колонке, не по строке; плотность важнее красоты; каждый лишний пиксель убивает сканируемость.
Домен: {{domain}} Объём: {{row_count}} строк Главная задача: {{primary_task}}
Принципы плотной таблицы (это критерии, не вкус)
- Глаз сканирует колонки, не строки. Числовые колонки — выравнивание по правому краю; текстовые — по левому. Никогда не центрируй.
- Tabular figures обязательны.
font-variant-numeric: tabular-nums— цифры одинаковой ширины. Без этого «99» и «100» в одной колонке прыгают. - Row height = task. Сканирование → 32-36px. Сравнение цифр → 40-44px. Чтение длинного текста → 48-56px. Не «комфортные» 64px по умолчанию.
- Не больше 7 колонок одновременно. Больше — column-toggle и persistence в URL.
- Sticky header — обязательно. При скролле колонки должны быть подписаны. На больших экранах — sticky первая колонка тоже.
- Hover — это feedback. Hover на строке = «эта строка активна», cursor: pointer если строка кликабельна, иначе — нет.
- Bulk-actions — отдельный режим UI. Чекбокс в первой колонке → при выборе появляется sticky-bar сверху или снизу с actions.
Что спроектировать
1. Анатомия колонки
| Тип данных | Выравнивание | Tabular | Truncation |
|---|---|---|---|
| ID / hash | left, monospace | да | middle ellipsis |
| Date | left или right | да | нет, формат сжатый |
| Money / number | right | да | нет |
| Status / badge | left | — | нет (chip фиксированной ширины) |
| Long text | left | — | line-clamp:1 + tooltip на hover |
| Actions (last) | right | — | icon-only, label в aria |
2. Sort + filter UI
- Sort: clickable header с иконкой состояния (none / asc / desc). По умолчанию неактивен; активный — bold/highlight. Shift+click для multi-sort, если в домене это релевантно.
- Filter: иконка фильтра в header колонки → popover с типом по данным:
- text → input + match mode (contains / starts / regex)
- number → range
- date → presets (today / 7d / 30d) + custom range
- enum → multi-select chips
- Applied filters: chips bar над таблицей. Каждый chip — × для снятия. Кнопка «Reset all».
3. Row actions
- Hover row actions: появляются справа при hover, icon-only с tooltip. На mobile — всегда видны (нет hover).
- Меню «…» (kebab): только если >3 actions. Иначе — inline.
- Primary row click: ведёт на detail page / открывает drawer. НЕ открывает modal внутри списка (теряется контекст).
4. Density modes
Три режима, переключатель в toolbar:
- Compact (32px) — для опытных пользователей, сканирование больших списков
- Default (40px) — стандарт
- Comfortable (52px) — для длинного текста или ozenки контента
Сохраняй выбор в localStorage / user pref.
5. Empty / loading / error
- Loading: skeleton-строки (5-7 штук), не spinner поверх пустоты.
- Empty (нет данных): иллюстрация + 1 строка пояснения + primary action («Add first {{domain}}»).
- Empty (фильтры дали 0): другой message: «Nothing matches» + кнопка «Reset filters».
- Error: инлайн в области таблицы, не toast. С retry.
6. Mobile fallback
Таблица на 375px не работает. Варианты:
- Карточки-стек: каждая строка → карточка с заголовком (главное поле), метаданными в столбик, actions внизу. Подходит для просмотра.
- Горизонтальный скролл со sticky 1-й колонкой: для тех, кому нужны все данные. Скролл-индикатор сверху обязателен.
- Adaptive: на mobile показывай 2-3 главные колонки, остальное — accordion при тапе на строку.
Выбор зависит от primary_task.
7. Performance (если row_count > 500)
- Virtual scrolling (react-virtual, tanstack-table virtualization).
- Pagination — серверная (limit + cursor / offset). Page size в toolbar: 25 / 50 / 100.
- Sort/filter — на сервере, не на клиенте.
Формат вывода
Колонки
Markdown-таблица: # | Колонка | Тип данных | Выравнивание | Width | Hidden by default? | Notes
Toolbar
Список элементов слева направо: search → filters → density → column-toggle → export → primary action.
Row spec
- Высота (компактный/дефолт/комфортный): X / Y / Z px
- Hover: ...
- Click: ...
- Row actions: ...
States
Заголовок + описание для: loading, empty (no data), empty (filtered), error, partial-error (одна ячейка не загрузилась).
Mobile
Описание выбранного подхода + где-почему.
Performance
Какие оптимизации применить при >500 строк, при >5000 строк.
Anti-patterns (НЕ делать)
- ❌ Центрирование чисел или дат. Глаз теряет колонку.
- ❌ Hover-actions без mobile-fallback. На touch-устройстве hover не работает.
- ❌ Modal для редактирования одной ячейки. Inline-edit или drawer — да; modal — нет.
- ❌ Spinner поверх таблицы при пагинации. Это сбрасывает контекст. Лучше skeleton-строки в области загружаемой страницы.
- ❌ Бесконечный скролл для критичных данных (счета, контракты). Юзер не вернётся к конкретной строке. Используй pagination.
- ❌ Цветной фон строки как единственный индикатор статуса. Это accessibility-провал. Цвет + иконка + текст.
- ❌ Showing all 23 columns by default. Спрячь редкие за column-toggle.
Billing-страница
Что показывать: план, история, способ оплаты, инвойсы, отмена.
Mobile-friendly аудит (375px)
Аудит мобильной версии на iPhone SE: тач-таргеты, скролл, попапы, tap-vs-hover, input zoom.
Сгенерировать варианты UI-компонента
Создать 4-6 разных подходов к компоненту с разным визуальным языком и трейд-оффами.