Web Interface Guidelines: a review checklist for the small decisions
Guidelines for building interfaces on the Web.
At a glance
- What is it?
- The Web Interface Guidelines repository is a living list of interface rules from the Vercel Labs team, mostly framework-agnostic with some React and Next.js specifics, covering focus, hit targets, loading states, animation and layout. It is best read as a review checklist for code you have already written, and its rules are opinionated enough that adopting them wholesale is a design decision.
- Who is it for?
- The Web Interface Guidelines fit a frontend team that wants a shared review vocabulary for details nobody argues about explicitly, such as focus rings, hit target sizes, minimum loading durations and optimistic updates, and it fits teams that want those rules available to coding agents in the repository.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 17 days ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 21, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A list of decisions rather than a design system
The premise in the first line of the README is that interfaces succeed because of hundreds of choices, and the repository is a living, non-exhaustive list of those decisions. That framing matters, because it is not a component library, not a token set and not a style guide with colour values. There is nothing to install and nothing to import into a design file. What there is, is a body of specific decisions with reasons, most of them framework-agnostic and some specific to React and Next.js, written in a form close to a code review comment. The file is the whole product, and the repository top level shows how small it is: a README, a LICENSE, an AGENTS.md, a command.md and an install.sh. There are no GitHub releases, so there is no versioned artifact to depend on either. The intended use is a designer or engineer working through their own interface and asking, one line at a time, whether each of these details is handled.
Focus rings, focus traps and a 24px minimum hit target
The Interactions section opens with accessibility rules that are specific enough to check in a diff. Keyboard works everywhere, with all flows keyboard-operable and following the WAI-ARIA Authoring Patterns, and every focusable element shows a visible, unobscured focus ring, with :focus-visible preferred over :focus so pointer users are not distracted, and :focus-within for grouped controls. The rule that sticky headers, footers, banners and overlays never cover the focused element is the kind of detail that is missed until a user complains. Focus management asks for focus traps and for moving and returning focus according to the WAI-ARIA patterns, which matters for modals and drawers. The size rules are numeric and easy to test: the visual target and the hit target must match, except that a visual target under 24px should have its hit target expanded to at least 24px, and on mobile the minimum is 44px. The viewport meta tag is given as a fallback for the mobile input rule.
Loading states that are told not to flicker
Two rules here are unusual enough to be worth reading twice. A loading button should show a loading indicator and keep the original label, so the control does not change width and does not lose its meaning mid-click. And a spinner or skeleton should have a short show-delay of roughly 150 to 300 milliseconds and a minimum visible time of roughly 300 to 500 milliseconds, both to avoid flicker on fast responses, with the note that the Suspense component in React already does this automatically. The second rule is a statement about perception, and it changes how a component library has to be configured. The neighbouring rules cover a different kind of continuity: state belongs in the URL so that share, refresh and Back and Forward navigation all work, and updates should be optimistic, with the interface changed immediately when success is likely and reconciled when the server answers, and an error with a rollback or an Undo on failure. The README also insists on not blocking paste, and on inputs that keep their focus and value after hydration.
Links stay links, and every gesture has a control
Several rules exist to stop the browser behaving badly, and the link rule is the clearest. Navigation uses a or Link, so that Cmd or Ctrl click, middle click and right click to open in a new tab all work, and a button or a div is never substituted for a navigational link. That sounds obvious and is a common mistake in component libraries that style everything as a button. The gesture rules are the accessibility counterpart: every drag, swipe, pinch or path-based action must also work with a tap or click control and with the keyboard, unless the gesture is essential, with a link to the WCAG guidance on dragging movements. Dragging gets its own rule, to disable text selection and apply the inert attribute while an element is dragged so that selection and hover do not happen at the same time. A related rule forbids dead zones, so that if part of a control looks interactive it should be interactive, and everything that uses useState is expected to be deep-linkable, including filters, tabs, pagination and expanded panels.
Animation rules that come down to transform and opacity
The Animations section is the most prescriptive part of the file, and it is largely a performance and accessibility specification. prefers-reduced-motion must be honoured with a reduced-motion variant, and the implementation preference is CSS first, then the Web Animations API, then a JavaScript library, stated as CSS over Web Animations API over libraries. Animation should target GPU-accelerated properties such as transform and opacity, and avoid properties that trigger reflows or repaints such as width, height, top and left. The rule against transition: all is explained in one line: an explicit list of the properties you intend to animate, typically opacity and transform, because all can animate layout-affecting properties and cause jank. The handful of CSS declarations the guidelines name are worth keeping in one place:
touch-action: manipulation
-webkit-tap-highlight-color
overscroll-behavior: contain
overscroll-behavior: none
transform-box: fill-box; transform-origin: center;The rubber-banding rule is the most conditional of them, since overscroll-behavior: none is only applied on html inside a media query for a fine pointer, so that pull to refresh survives on touch devices, and the note warns that none also disables scroll chaining and native swipe navigation, and that hybrid touch devices need separate testing.
Optical alignment over geometric alignment
The Layout section starts from a premise that unsettles a lot of design token work: perception beats geometry, so optical alignment means adjusting by plus or minus one pixel when that is what looks right. Beside it, deliberate alignment requires that every element aligns with something intentional, whether a grid, a baseline, an edge or an optical center, with no accidental positioning. The reasoning is that an element placed by the layout engine by default is not aligned, it is merely unrounded. The remaining layout guidance continues the same tension between what the browser does and what the eye wants, and the section also warns about a specific trap for teams that use drag interactions, which is that a dragged element should be inert so that hover and selection do not fight the gesture. For a team that measures everything in tokens, this is the part of the file that will generate arguments, and that argument is the point. The rules are not neutral, they encode a preference for interfaces that look correct to a person rather than merely consistent in code.
Adopting it: install.sh, command.md and AGENTS.md
Because the artifact is prose, the interesting question is how a team puts it to work, and the repository layout points at three answers. The install.sh script at the top level suggests the guidelines can be placed where a tool will read them, command.md looks like a reference for a command you can run, and AGENTS.md is the file that coding agents read for instructions in a repository. The README itself asks for feedback and links to the repository for it, which is consistent with a document that is expected to change. The practical forms of adoption are therefore several. A team can keep the file open as a review checklist, paste the relevant section into a pull request template, encode a subset of the rules as lint rules, and point an agent at it so that generated interface code follows the same conventions. The last option is the one the repository structure is built for, and it is also the one that needs the most care, because a machine will apply a rule literally while the guidelines repeatedly ask for judgement, such as only animate when motion clarifies cause and effect.
The limits of a checklist, and the alternative to one
The honest limitation is that this is a list of suggestions with no priority order, no severity levels and no exceptions, and the README says so, calling it non-exhaustive and living. A rule like minimum loading-state duration of roughly 300 to 500 milliseconds is a starting point, not a constant, and applying it as one will make interfaces feel slow. Another limitation is that the rules assume a conventional web application, one with a URL, forms, modals and a navigation model, and a product that is a single page application without server reconciliation will find the optimistic update rule awkward. The alternative to a written checklist is a component library with the decisions already made, where the focus trap, the loading button and the toast come pre-built, and the difference in approach is exactly what you are choosing between: a library constrains you to the cases its author handled, and a checklist leaves every decision with the person reading it. A mature product with its own conventions will find the checklist more useful as a source of arguments than as a set of instructions.
Editorial conclusion
The Web Interface Guidelines fit a frontend team that wants a shared review vocabulary for details nobody argues about explicitly, such as focus rings, hit target sizes, minimum loading durations and optimistic updates, and it fits teams that want those rules available to coding agents in the repository. It does not fit a team that wants a component library to copy from, and it does not fit a product whose existing interaction model deliberately departs from browser conventions. Read the rules against your own product before turning them into a lint rule, and treat the open-ended items such as the spinner timings as starting points rather than constants. The last push to the repository was on 2026-10-05, and the project publishes no GitHub releases.
Frequently asked questions
What is the Web Interface Guidelines repository?
It is a living, non-exhaustive list of interface decisions published by Vercel Labs, covering interactions, animations and layout, with most guidelines framework-agnostic and some specific to React and Next.js. The README invites feedback on the document itself.
Does the Web Interface Guidelines define a colour palette or design tokens?
No. The file is about interface decisions such as focus behaviour, hit target sizes, loading states, animation properties and alignment, not about visual tokens or a component library. The repository contains a README, a LICENSE, an AGENTS.md, a command.md and an install.sh.
What minimum touch target size do the guidelines require?
The visual target and the hit target should match, except that a visual target smaller than 24px should have its hit target expanded to at least 24px, and the minimum on mobile is 44px. Input font size should be at least 16px on mobile to prevent iOS Safari from zooming on focus.
How long should a loading indicator stay visible?
The guidelines ask for a short show-delay of roughly 150 to 300 milliseconds and a minimum visible time of roughly 300 to 500 milliseconds, to avoid flicker on fast responses, and note that the Suspense component in React does this automatically. A loading button should show an indicator and keep its original label.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/vercel-labs-web-interface-guidelines)Was this useful?