Checkable UX rules UX-1…UX-80 and mockup checklists (forms, feedback, navigation, states, accessibility), read by ui-design, frontend and reviews. Directly for «проверь макеты по UX». Code: web-design-guidelines.
Resources
1Install
npx skillscat add idontlikedrinkpivo/web-dev-pipeline-codex-plugin/ux-patterns Install via the SkillsCat registry.
Codex runtime. Before using this skill, read
../executor-catalog/references/codex-runtime.md. It defines tool mappings, named-agent dispatch and stage-chat orchestration; use it for inherited Claude Code terms below.
UX Patterns
A component library can be assembled any way. These rules keep the result
usable. Three rule sets this plugin embeds tag each rule that overlaps one
here with its UX-<n>: web-design-guidelines (code-level detail behind
Section 8), ui-ux-pro-max (style data and a searchable mirror of these
rules) and frontend-design (taste rules for drawing). Where one of them
disagrees with this file, this file wins and the other is the one to fix.
Where the rules come from, and the disagreements already settled:references/sources.md; read it when a rule is challenged.
Every rule is checkable on a screen-spec row, a frame screenshot, or a diff. A
rule nobody can check is not in this file.
Ids are append-only, so a later rule sits in its section out of numeric
order: UX-57–62, 66 — Section 1; 63, 67 — 2; 69 — 3; 70, 80 — 4; 64, 65,
68 — 5; 71–73 — 6; 74–77 — 8; 78, 79 — 9.
Product type
The frames register names it (ui-design → Тип продукта):
| Type | Who | Defaults |
|---|---|---|
B2B |
internal or business tool; trained, returning, mostly desktop users behind SSO | density, tables, sidebar, efficiency over persuasion |
B2C |
public consumer web; anonymous, impatient, often mobile users | conversion, trust, performance, consumer law |
A product with both faces (a public site plus an admin) names the type per
area; a screen follows the type of its area. When a rule below has no
type column, it holds for both.
Both types are desktop first: the main width is the desktop one, drawn
and built first, and the narrow width must work (UX-74).
Who applies what
Which reader applies which sections — ui-design, the Figma builders,screen-spec, frontend, the reviews, ui-test-cases — is inreferences/readers.md; read it when deciding whether a rule is yours to
apply or only to check.
A screen spec, frame or diff that must break a rule (a product constraint, a
legal text) says so next to the place, with the rule id. Silence is a
finding.
1. Visual system — using the library
- UX-1 Tokens only. Spacing from the scale (4-px base, multiples of 8
for layout gaps and padding); colours from semantic tokens (primary,secondary,muted,destructive,border,ring, …); no raw hex,
nomt-[13px]. A new colour is a new token in light and dark. - UX-2 One component per purpose. The same thing looks and behaves the
same on every screen. A missing variant is added once to the component
(its variants definition), never as per-screen overrides. - UX-3 Type scale. At most three text sizes and three weights per
screen; headings in order (h1once, no skipped levels — a smaller look
is a style, not a lower tag). Emphasis by weight before colour. - UX-4 Line length 50–75 characters for running text (
max-width
≈ 70ch); page content has a max width. - UX-5 Hierarchy reads top to bottom: title → content → actions. Related
items grouped by spacing, unrelated separated; the most important
content gets the most space and contrast, top-left; a heading has more
space above it than below, so it belongs to what follows. - UX-6 Colour never carries meaning alone (WCAG 1.4.1): an error, a
status, a required mark also has text or an icon. - UX-7 Contrast: text 4.5:1, large text 3:1, control boundaries,
icons and focus ring 3:1 (WCAG 1.4.3, 1.4.11). Kit defaults are checked,
not assumed. - UX-8 Icons have visible labels. Icon-only only in a dense toolbar,
then with a tooltip and an accessible name. - UX-9 Targets: at least 24×24 px (WCAG 2.5.8). B2C and every touch
width: 44×44 px, with at least 8 px between neighbouring targets. - UX-10 Density: B2B — compact rows 32–40 px; B2C — 48 px and more.
- UX-57 Icons: one set, SVG, one style per hierarchy level (outline or
filled, one stroke width), sizes from tokens. An emoji is never an icon. - UX-58 Depth and shape: one shadow (elevation) scale and one radius
scale for the whole product; blur only behind a modal or a panel, never
as decoration. - UX-59 Text: body line height 1.5–1.75, default letter spacing; on
narrow widths body text and inputs at least 16 px; numbers in columns,
totals and timers use the font's tabular figures (tabular-nums), not a
monospace face; short multi-line headingstext-wrap: balance. Every
family has thecyrillicsubset and loads with it (Next.jsnext/font:subsets: ['latin', 'cyrillic']), or Russian text falls back to a
system face. - UX-60 No template tells — the defaults that make a screen look
generated: no ALL-CAPS labels above content; no single accented word in a
heading; «01 / 02 / 03» markers only when the content is a sequence; no
«→» appended to button or link text; no «A · B · C» meta strings as
decoration; content is not chopped into identical cards with one shadow;
a gradient only when it carries meaning; a big number with a small label
and a gradient on the first screen only when it is truly the best option.
The six generated-look clusters are infrontend-design. - UX-61 Motion only answers an action or shows what changed (opened,
saved, moved): no decorative entrances, staggered reveals or animated
hover on non-interactive cards, no spring curves, no animated transitions
between screens; a B2C first screen may have one orchestrated moment
(parallax only there). What people do a hundred times a day, and every
keyboard action (a shortcut, the command palette), is not animated; a
pressed button may shrink toscale(0.97). Animatetransformandopacityonly, nevertransition: all; durations and easing are the
motion tokens ofweb-design-guidelines→ Motion — exit faster than
entry, ease-out in and out, never ease-in; an animation is interruptible
and never blocks input; endless motion only in loading indicators;
anything that moves on its own for more than 5 s (carousel, video) has a
pause.prefers-reduced-motionremoves movement — slides, scaling,
parallax, smooth scrolling — and keeps fades and colour changes, so a
change of state is still seen; smooth scrolling is only for anchors on
long pages. - UX-62 Dark theme (when the SRS has one) is designed together with the
light one, and contrast is checked in each separately;color-scheme,theme-colorand the native<select>colours are set. - UX-66 Text alternatives: a meaningful image has
alt, a decorative
onealt=""; a decorative icon next to text is hidden from screen
readers (aria-hidden); video and audio have captions or a transcript.
2. Actions
- UX-11 One primary action per screen and per modal (a temporary
side panel may have its own). Others are secondary, outline or ghost.
Two filled buttons side by side is a finding. - UX-12 Labels are verb + object in sentence case: «Сохранить
изменения», «Удалить бронь». Never «ОК»/«Да» answering a question. - UX-13 Order is consistent across the product: on a page or form the
primary comes first (left), secondary after it; in a dialog the primary
is last (right). The same order on every page and in every dialog of
the product. - UX-14 Do not disable Save/Submit. Keep it enabled and show the errors
on press. A control disabled for another reason says why next to it; an
action the user can never have (permissions) is hidden. - UX-15 While a request runs the triggering control shows progress and
ignores repeated presses — a busy state, not thedisabledattribute,
so focus stays on it; the server is idempotent anyway. - UX-16 Groups: 2–3 actions in a row; more go into a menu.
- UX-63 Control states: every interactive element has hover, pressed,
focus and disabled states; focus is always visible (:focus-visible),
and removing the outline without a replacement is a finding; hover and
focus raise contrast; the reaction is instant or within 150 ms, with a
pointer cursor; non-interactive cards do not react to hover; an input
looks like an input; read-only looks and is marked differently from
disabled. - UX-67 Drag and gestures have an alternative: every drag has a
single-tap and keyboard way (buttons «Выше» / «Ниже», a «Переместить»
menu); every swipe has a visible control (WCAG 2.5.7).
3. Forms
- UX-17 One column, label above the field. A placeholder is never the
label and is used only in a search field («Поиск по названию…»); a format
example lives in the hint (UX-19). - UX-18 Marking: B2B — «(необязательно)» on optional fields only.
B2C —*on required and «(необязательно)» on optional (Baymard:
marking only optional fields makes 32% skip required ones). Keep
optional fields few; in B2C cut every field the flow can live without. - UX-19 Field fit: width matches the expected length; mobile keyboard
and autofill viatype/inputmode/autocomplete(WCAG 1.3.5),autocomplete="off"only where browser autofill misleads (search,
internal codes);spellcheckoff in emails, codes and logins;inputmode="numeric|decimal"instead oftype=number; paste is never
blocked; formats are accepted loosely (spaces, dashes) and explained
beforehand in a hint between the label and the field; a password field
has «Показать пароль». - UX-20 Validation timing: on blur, never while typing; the error
clears as soon as the value is fixed; everything is checked again on
submit and on the server. B2C: a positive check mark on complex fields
(password, email). - UX-21 Error copy is an instruction in the question's words
(«Введите email в формате name@example.com»), placed directly under the
field and tied to it witharia-describedby. Never «Неверное значение»,
«Упс». - UX-22 After a failed submit: an error summary at the top that takes
focus and links to the fields, the same messages at the fields, the page
title prefixed «Ошибка:». Entered values are kept — card data included.
A one-field form (search, an SMS code) has no summary: focus returns to
the field. - UX-23 Do not ask twice for what the flow already has (WCAG 3.3.7):
billing = shipping by default, no «repeat password/email». - UX-24 Long forms: steps with clear names, Back/Next with descriptive
labels, save and continue. Autosave only for toggles; text fields have
an explicit Save; do not mix the two in one form. A long form keeps a
draft in the browser and offers «Восстановить черновик» on return; it
reaches the server only through the explicit Save. - UX-69 Label and field are one: clicking the label focuses the field;
a checkbox or radio label is part of its hit area; related fields are
grouped under a heading (fieldset/legend); rarely used settings sit
behind «Дополнительно».
4. Feedback, loading, notifications
- UX-25 Response thresholds: under 1 s — no indicator; 1–10 s — a
skeleton in the content's shape for a page or table, a spinner only for
a small module; over 10 s — progress with a percentage or «3 из 50» and
what is happening. - UX-26 Refresh keeps data visible and shows when it was updated; a
skeleton never replaces data the user is reading. - UX-27 Toast is for success only, short, one at a time, 4–10 s,
announced withrole="status". Errors and messages that ask for an
action never disappear on their own: inline at the place, or a banner.
B2C: a reversible action's toast carries «Отменить» and stays 10 s,
paused while hovered or focused. - UX-28 Status messages are announced without moving focus
(role="status", WCAG 4.1.3). A field error is tied to its field
(aria-describedby) and announced politely when it appears;role="alert"only for a failed operation (the request did not go
through); after a failed submit focus moves to the summary (UX-22). - UX-29 Optimistic update only for operations that almost always
succeed (toggle, like): snapshot, update, roll back with an inline error.
Never for payments or destructive actions. - UX-70 A count change is announced as a phrase — «В корзине 3
товара», not a bare number — without moving focus; not every badge is
its own live region. - UX-80 AI-generated content is labelled: an answer or text produced by
AI is marked as such next to it, and the user knows they are talking to
AI (the EU AI Act, Art. 50, requires it). Streaming the answer and rating
it are features — only when the SRS has them.
5. Navigation, dialogs, destructive actions
- UX-30 Navigation stays visible on desktop (no hamburger there).
B2B — left sidebar when there are many sections. B2C — top navigation;
on mobile a bottom bar for 3–5 equal sections, otherwise Priority+
(«Ещё»). - UX-31 Where am I: the active item has
aria-current="page"; every
page has a unique<title>starting with itsh1; breadcrumbs only
for hierarchies three levels deep and more. - UX-64 Semantics and keyboard: an action is a
<button>, a navigation
is a link (Ctrl/Cmd-click opens a new tab), never a clickable<div>;
everything works from the keyboard in reading order; pages with
navigation have «Перейти к содержимому»; after a route change in a
single-page app focus moves to the main content and the tab title
updates (UX-31). - UX-65 Focus not obscured: sticky headers, panels, banners and chat
widgets never cover the focused element (WCAG 2.4.11); anchored headings
havescroll-margin-top. - UX-68 Help in one place: help, contacts and the support chat sit in
the same place on every page (WCAG 3.2.6). - UX-32 Shareable state lives in the URL — filters, tab, page, the
open item; Back closes an overlay that looks like a page and returns a
list to the same position. - UX-33 Modal only for a critical warning, data the task cannot
continue without, or a short rare task. Frequent tasks stay on the page;
editing that needs the context beside it goes to a non-modal side panel.
B2C on mobile: a bottom sheet with a visible Close for short tasks, a
full-screen page for long ones. Never a modal on a modal. - UX-34 Dialog behaviour (WAI-ARIA APG):
role="dialog",aria-modal, a visible title as its name; Tab cycles inside, Esc
closes, focus returns to the trigger; first focus is the first control,
or the least destructive one when the action is irreversible. While the
dialog's own request is running, Esc and the cancel button do not close
it: the answer — a refusal included — must land where the user is looking. - UX-35 Unsaved changes are guarded: leaving inside the app asks
«Уйти без сохранения?»; closing the tab usesbeforeunload. - UX-36 Reversible → undo, irreversible → confirm. A confirmation names
the object in bold and its consequence («Удалить бронь X?
Документы удалятся. Отменить нельзя.»), its button repeats the verb
(«Удалить бронь»), and it is not the default focus. Confirmations
for everything are a finding — users stop reading them. - UX-37 Danger styling at every step: a destructive action is red
wherever it appears — on a page or in a menu as a danger control of
secondary weight (red text or outline, never the filled primary), set
apart from the primary action (its own group, a divider, or an «Опасная
зона» section at the end); in the confirmation the confirming button is
the filled red one. «Выйти» and «Удалить аккаунт» stand apart from the
ordinary menu items; only the second is red. Type-to-confirm (the
object's name) only for high risk: cannot be recreated, or breaks other
objects. - UX-38 Sessions: warn before expiry (≥2 min, extend with one action,
WCAG 2.2.1), say whether work is kept, and keep it across re-login
(2.2.5). Login allows paste and password managers, no cognitive test
without an alternative (3.3.8).
6. Data screens and states
- UX-39 Table or cards: comparing items by attributes → a table whose
first column is a human-readable name; B2C browsing visual items → grid
of cards (5 essentials: price, title, image, rating with count,
variants). - UX-40 Columns: numbers right-aligned, text left; long headers wrap to
two lines then truncate with the full text in a tooltip; sticky header on
long tables; a visible cue for horizontal scroll; a sortable column shows
its direction (aria-sort); money and percentages keep a fixed number
of decimals (2 and 1–2); the header is sentence case on the table's own
background, rows without zebra stripes; a total equals the sum of the
rows as shown, rounding included. - UX-41 Row and bulk actions: checkboxes plus a bulk bar above the table
(≤5 actions, rest in a menu); per row a menu, or up to two inline
icon buttons. - UX-42 Filters: applied filters visible as removable chips with
«Сбросить всё»; B2B and desktop — apply instantly; B2C mobile — a filter
sheet with «Применить». No scroll-to-top on every change. - UX-43 Paging: search, compare and return tasks → pagination (hidden
when one page; first, last, neighbours, «…»; page number in the title).
B2C catalog → «Показать ещё» with lazy loading and Back to the same
position. Infinite scroll only for feeds, and never where a footer
matters. - UX-44 Three different empty states: first use — what this is for and
one primary «Создать …»; no results — «Ничего не найдено» and
«Сбросить фильтры», the count still visible; never «Нет записей» that is
replaced by data a moment later. The empty state replaces the table, not
a blank grid under its header. - UX-45 Error state says what happened and what to do («Повторить»), in
plain words, next to the failed part; the rest of the screen keeps
working. - UX-46 Forbidden: permanently unavailable → hidden; available later →
disabled with «Доступно, когда …»; data the user cannot see → an
explanatory state with a way forward (ask for access). - UX-47 Dashboards: few metrics, the key one largest and first; bars and
lines, not pies, donuts, gauges or 3D — parts of a whole are a 100 %
stacked bar or horizontal bars with values; the same series keeps its
colour everywhere; a KPI shows its comparison window. A change is
coloured by good or bad for the user, not by up or down (fewer
complaints is green), a zero change is neutral grey; a real zero prints
«0», a missing value «—». - UX-71 Long content: long words, links and ids wrap
(overflow-wrap: anywhere,min-w-0on flex children) instead of
breaking the layout; what matters — actions, errors, names, headings — is
never clamped; clamped secondary text is reachable in full, not by hover
only; nothing is lost at 200 % text zoom or at the narrow width (WCAG
1.4.4, 1.4.10, 1.4.12); a screen is checked with short, average and very
long values. - UX-72 Badges and chips: a badge is a status — not clickable, never
colour alone; a chip is a value or an action — a button with a selected
state; a badge or chip label stays whole on one line; a chip set wraps,
and what does not fit sits behind an expandable «+N». - UX-73 Charts: the legend sits next to the chart; axes have labels and
units; exact values on hover and from the keyboard; series differ by more
than colour; a text summary or a table for screen readers; their own
Loading, Empty and Error states (UX-25, UX-44, UX-45); thousands of points
are aggregated; numbers and dates throughIntl(UX-77); 4–7 ticks on
the value axis; category labels are never rotated (shorten them or turn
the bars horizontal); one series needs no legend.
7. B2C additions
- UX-48 Performance is UX (Core Web Vitals at p75): LCP ≤2.5 s,
INP ≤200 ms, CLS ≤0.1. Every image and video has its size oraspect-ratio; the hero image isfetchpriority="high"and never lazy;
lazy loading below the first screen only. - UX-49 First screen: the value proposition and one primary CTA; the
rest in scannable sections below — people scroll when the top promises
something. Social proof is concrete (name, role), never small numbers. - UX-50 Price and trust: the total, delivery and returns are visible as
early as the product page; no fee appears for the first time at the last
step. - UX-51 Account later: guest path first, account creation after the
goal (purchase, booking). Password rules shown before typing (the
show-password toggle is UX-19); passkeys and social sign-in say what
happens to the account. - UX-52 Onboarding is contextual help at the moment of need, not a
carousel tour; if a tour exists, «Пропустить» is visible on every card. - UX-53 No deceptive patterns: no confirmshaming, pre-checked consent,
items added without asking, fake urgency or scarcity, cancellation
harder than sign-up, hidden or drip fees. Legally binding in the EU (DSA
Art. 25, GDPR/Planet49) and partly in the US (ROSCA, state
auto-renewal laws, FTC Junk Fees Rule). - UX-54 Cookie consent: the first layer has «Принять все», «Отклонить
все» and «Настроить» with equal weight; withdrawing is as easy as
giving; nothing pre-selected. - UX-55 Mobile web: never disable zoom, never lock orientation; primary
actions within thumb reach at the bottom of tall screens. Motion is
UX-61. - UX-56 Localisation-ready: room for text growth (short strings up to
+200%), CSS logical properties,langanddirset; no text inside
images. Dates, numbers and money are UX-77.
8. Implementation — for code
Checked in the code by frontend and the code-review-unit UI lens. The
code-level detail of each rule — the attributes, CSS properties and
anti-patterns to flag — is in web-design-guidelines, marked with these ids.
- UX-74 Layout: desktop first — the main width is the desktop one (the
first in the register's Ширины), drawn and built first, and the
narrow width must work; the page never scrolls sideways (a table scrolls
inside itself, UX-40);dvhinstead of100vh; full-bleed layouts keepenv(safe-area-inset-*); fixed bars never cover content; onez-index
scale;overscroll-behavior: containin modals and drawers; images never
wider than their container; layout by flex and grid, not by measuring in
JS. - UX-75 Performance in code (both types; the Core Web Vitals budgets for
B2C are UX-48): lists longer than ~50 rows are virtualised or paginated
(UX-43); search-as-you-type is debounced; no layout reads during render;
code split by route; third-party scriptsasync/defer; every image
has its size, and below the first screenloading="lazy"; fontsfont-display: swap, only the critical ones preloaded; video instead of
GIF; space reserved for content that loads later. - UX-76 Touch on narrow widths:
touch-action: manipulation; the tap
highlight colour set on purpose;autoFocusonly on desktop and only for
a single main field; text selection off while dragging. - UX-77 Dates, numbers and money through
Intlin every product; brand
names, codes and ids carrytranslate="no".
9. Texts in Russian
- UX-78 Typography: «ёлочки» quotes, „лапки“ inside them; the ellipsis
is one character «…»; waiting states read «Загрузка…», «Сохранение…»; a
spaced em dash «—» in text; a no-break space between a number and its
unit («10 МБ», «5 мин»), in «№ 5» and «т. е.»; counts in digits
(«8 проектов»); a capital only on the first word (UX-12). - UX-79 One action, one name: the button «Опубликовать» produces
«Опубликовано»; things are named in the user's words, not the system's
(«уведомления», not «вебхуки»); active voice; errors do not apologise and
are never vague (UX-21, UX-45); an empty screen invites the next action
(UX-44); the user is «вы» in lower case; sections are named without
pronouns («Проекты», not «Мои проекты»), «мои» only next to someone
else's. No selling words in an interface: «бесшовный», «раскройте
потенциал», «всё в одном», «не просто X, а Y», «революционный»; no
invented figures, reviews or customer logos (UX-49).
Полнота макета
The completeness checklist. ui-design runs it twice: on the screen set
before drawing (it becomes the per-screen plan in the Figma packet), and on
the file after drawing or indexing (each miss is a redraw or a question to
the designer). Every item is checkable from the frames: their names, the
layer names by action, the annotation, the screenshot. An item that cannot
apply to a screen is skipped, not drawn for show.
- Every flow is reachable. Each use case's Main flow, every
Alt-n
and everyExc-nwith a human actor has a frame, a state, or a nested
step on some screen where the actor meets it; the annotation cites the
flow id. - Every role sees its actions. For each role on a screen, the actions
it has are drawn; the ones it must not have are hidden, or disabled with
the reason when available later (UX-46). A screen two roles share shows
the difference on a frame or on the annotation. - Every data screen has its states: Loading (UX-25), Empty — each kind
the screen can have (UX-44), Error with a way to retry (UX-45), and
Forbidden when an SRS exception says the actor may not see the data
(UX-46). - App-wide states exist once: session expired (UX-38), too many
requests, server error, offline — each a frame the whole product shares. - Every destructive action is guarded: undo when it is reversible, a
confirmation naming the object and the consequence when it is not
(UX-36, UX-37). - Every field has its validation error — one per rule the SRS gives
it (required, format, limit), under the field (UX-21), and the failed
submit has its summary (UX-22). - Every result without navigation has success feedback — saved,
cancelled, N found — as a status message (UX-27, UX-28). - Every action that waits shows progress and ignores a repeat press
(UX-15), on the frame or on the annotation. - Every text is on the «Тексты» table of the screen's annotation: each
action, state message, error, success message and step title above. - Every screen that collects personal data shows the notice. When the
SRS marks a field as personal data (phone, email, name, address), the
screen that first collects it says what it is used for and links the
processing policy, with an unticked consent where the SRS or the law
asks for one (UX-53); the text is on «Тексты». A sign-in by phone code
is such a screen.
Проверка экрана перед сдачей
The checklist a built screen passes. impl-ui runs it before handing a
screen unit over and reports each item; the code-review-unit UI lens
checks it; ui-test-cases covers the items a screenshot shows when it
compares a screen with its frame. An item that cannot apply is skipped.
- Every width in the register's Ширины, the desktop one first:
nothing clipped, no sideways page scroll (UX-74). - Keyboard only: the whole screen works without a pointer; focus is
always visible and never covered (UX-63, UX-64, UX-65). - Contrast of text and controls in every theme the product has (UX-7,
UX-62). - Reduced motion: with
prefers-reduced-motionnothing slides or
scales; only fades, colour changes and loading indicators remain (UX-61). - Zoom: at 200 % and at the narrow width nothing is lost (UX-71).
- Value lengths: short, average and very long values keep the layout
(UX-71). - Icons from one set, no emoji; icon-only buttons have a name (UX-57,
UX-8). - Texts follow Russian typography and one name per action (UX-78,
UX-79).
How to cite
A spec row, a frame annotation, a test name or a review finding cites the
rule as UX-<n>. A deliberate exception is written next to the place:
«Исключение UX-14: кнопка заблокирована, пока идёт загрузка файла —
требование SRS FR-…».