Rams MCP · The full engine, now in your coding agent
vuetifyjs on GitHub

vuetifyjs/vuetify

Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.

30 files reviewed·August 1, 2026

View on GitHub

Elevated

Accessibility needs attention.

9issues
Critical, Serious & Moderate · top 6 shown below

Top fix

Add keyboard and touch support to copy and playground buttons

See the fix

Verdict

Vuetify's docs look polished for mouse users but fall apart for anyone else: no keyboard access to copy or playground actions, no focus states, and TOC hit targets too small to tap. The biggest risk is that these gaps compound, since the same hover-only logic repeats across headings, TOC, and code blocks.

Files Rams reviewed

packages/docs/src/components/app/Heading.vue

packages/docs/src/components/app/Link.vue

packages/docs/src/components/app/Markdown.vue

packages/docs/src/components/app/Markup.vue

packages/docs/src/components/app/Toc.vue

packages/docs/src/components/app/TooltipBtn.vue

packages/docs/src/components/app/bar/Bar.vue

packages/docs/src/components/app/bar/EcosystemMenu.vue

packages/docs/src/components/app/bar/LearnMenu.vue

packages/docs/src/components/app/bar/NotificationsMenu.vue

packages/docs/src/components/app/bar/SupportMenu.vue

packages/docs/src/components/app/drawer/Drawer.vue

packages/docs/src/components/app/drawer/PinnedItems.vue

packages/docs/src/components/app/list/List.vue

packages/docs/src/components/app/search/Search.vue

packages/docs/src/components/app/search/SearchDialog.vue

packages/docs/src/components/app/search/SearchGroup.vue

packages/docs/src/components/app/search/SearchResults.vue

packages/docs/src/components/app/settings/options/OfflineOption.vue

packages/docs/src/components/app/settings/options/ThemeOption.vue

packages/docs/src/components/app/BackToTop.vue

packages/docs/src/components/app/Btn.vue

packages/docs/src/components/app/Caption.vue

packages/docs/src/components/app/CommitBtn.vue

packages/docs/src/components/app/Divider.vue

packages/docs/src/components/app/Figure.vue

packages/docs/src/components/app/Headline.vue

packages/docs/src/components/app/Sheet.vue

packages/docs/src/components/app/Table.vue

packages/docs/src/components/app/TextField.vue

88/100

Accessibility

2 critical3 serious
AccessibilityCritical

packages/docs/src/components/app/Markup.vue:33

Copy and open-in-playground buttons don't exist for keyboard or touch users

Both the copy-source v-btn and the open-code v-btn in Markup.vue are wrapped in `v-if="isHovering"`, so they are removed from the DOM entirely until a mouse hover fires. There's also no `aria-label` set, only a `v-tooltip` for the visible label. A keyboard user tabbing through the page, or any touch-screen user, never triggers `isHovering` and never gets these controls in the tab order at all.

Why it matters

Keyboard and touch users are completely locked out of copying code samples or opening them in the Playground, since the controls never render for them, not even as an unlabeled button.

Fix

Keep interactive controls mounted in the DOM at all times and use CSS opacity/visibility for hover reveal, and give icon-only buttons an explicit aria-label so their name doesn't depend on tooltip hover.

<v-btn
  v-if="isHovering"
  :key="icon"
  :icon="icon"
  class="text-disabled me-3 mt-2 app-markup-btn position-absolute right-0 top-0"
  density="comfortable"
  size="small"
  v-bind="activatorProps"
  variant="text"
  @click="copy"
/>
<v-btn
  :key="icon"
  :icon="icon"
  :aria-label="t('copy-source')"
  :class="['text-disabled me-3 mt-2 app-markup-btn position-absolute right-0 top-0', { 'opacity-0': !isHovering }]"
  density="comfortable"
  size="small"
  v-bind="activatorProps"
  variant="text"
  @click="copy"
/>
AccessibilityCritical

packages/docs/src/components/app/Toc.vue:115

Sponsor promotion link has no accessible name at all

The sponsor ad anchor in Toc.vue wraps only a `<v-img :src="spot.spot.image.url" />` with no `alt` attribute and no surrounding text. The link (`<a :href="spot.spot.href" ... target="_blank">`) has zero text content and zero accessible name.

Why it matters

A screen reader user tabbing to this link hears nothing describing where it leads or what it promotes, an unlabeled link in a list of otherwise well-labeled navigation items.

Fix

Every image that is the sole content of a link must carry descriptive alt text so the link has an accessible name.

<v-img :src="spot.spot.image.url" />
<v-img :src="spot.spot.image.url" :alt="spot.spot.sponsor ? `Sponsored by ${spot.spot.sponsor}` : 'Sponsor advertisement'" />
AccessibilitySerious

packages/docs/src/components/app/Heading.vue:7

Heading anchor link hidden from every screen reader user

The deep-link anchor inside Heading.vue (the "#" router-link that lets readers copy a link to a section) is wrapped in aria-hidden="true". That doesn't just hide the decorative '#' glyph, it removes the entire interactive link from the accessibility tree, so a screen reader user has no way to discover or activate it at all.

Why it matters

Sighted mouse users can hover to reveal and copy section links; screen reader users are silently denied the same capability, making deep-linking to documentation sections a sighted-only feature.

Fix

Never apply aria-hidden to an element that contains the only instance of an interactive control; hide decorative glyphs individually and give the link an accessible name instead.

<router-link
  v-if="href"
  :to="href"
  aria-hidden="true"
  class="text-decoration-none text-end text-md-start d-none d-sm-inline-block"
  style="user-select: none"
>
  <span class="text-primary">#</span>
</router-link>
<router-link
  v-if="href"
  :to="href"
  :aria-label="t('copy-link-to-section')"
  class="text-decoration-none text-end text-md-start d-none d-sm-inline-block"
  style="user-select: none"
>
  <span class="text-primary" aria-hidden="true">#</span>
</router-link>
AccessibilitySerious

packages/docs/src/components/app/Toc.vue:32

Active table-of-contents entry is marked by color alone

The active TOC list item gets `'text-primary router-link-active'` as its only distinguishing class versus the default `text-medium-emphasis` styling on every other entry. There's no weight, icon, or underline change alongside the color shift.

Why it matters

Colorblind users scanning the table of contents can't tell which section is currently active, since the only signal is a color difference between two otherwise identically styled list items.

Fix

Pair any color-only state indicator with a second non-color cue such as font weight or an icon so the state is visible without color perception.

'text-primary router-link-active': activeItem === to.slice(1),
'text-primary router-link-active font-weight-bold': activeItem === to.slice(1),
AccessibilitySerious

packages/docs/src/components/app/Heading.vue:61

Anchor link has no visible focus state for keyboard users

The `.v-heading > a` rule sets opacity: 0 for `&:not(:hover):not(:focus)`, meaning the link only becomes visible on hover or focus, but no distinct focus style (outline, background, underline) is defined beyond the opacity toggle. A keyboard user tabbing through the page sees the link pop into view with zero visual differentiation from its resting state, no outline to confirm where focus landed.

Why it matters

Without a clear focus indicator, keyboard users lose track of which element is active as they tab through headings, making it hard to confirm the anchor link is focused before pressing Enter.

Fix

Pair any focus-triggered visibility change with an explicit focus-visible outline so keyboard focus location is always unambiguous.

&:not(:hover):not(:focus)
  opacity: 0
&:not(:hover):not(:focus)
  opacity: 0

&:focus-visible
  opacity: 1
  outline: 2px solid currentColor
  outline-offset: 2px
98/100

Spacing

1 serious
SpacingSerious

packages/docs/src/components/app/Toc.vue:30

Table-of-contents links have a hit target well under 44px

Each TOC entry (`a.v-toc-link`) sits inside an `li` styled with `py-1` (4px top/bottom padding) around `text-body-medium` text, yielding a tap target that's roughly 20-24px tall total.

Why it matters

On mobile, tapping between adjacent TOC entries becomes error-prone when the vertical padding leaves a target well below the ~44px minimum recommended for reliable touch accuracy.

Fix

Give list-based navigation links enough vertical padding to reach a comfortable touch target, even when the visible text stays small.

'ps-3 text-medium-emphasis text-body-medium py-1 font-weight-regular',
'ps-3 text-medium-emphasis text-body-medium py-2 font-weight-regular',

Typography

No issues found

Color

No issues found

Components

No issues found

Motion

No issues found

UX

No issues found

Craft

No issues found

Working well

  • Skipping the contents of `link_close`/`link_open` pairs before autolinking commit hashes and issue numbers is a careful touch: it prevents the regex from mangling text that's already inside a hand-authored markdown link.
  • The IntersectionObserver-driven active TOC tracking with a stack (activeStack) correctly handles overlapping sections scrolling in/out, which is a subtle scroll-sync detail most implementations get wrong.
  • Deriving the tag and classes from props.level via a HEADING_CLASSES map keeps heading semantics (h1-h5) correctly decoupled from visual size, which is the right pattern for accessible heading structure.
  • The icon placement logic correctly mirrors context: a leading pound icon for same-page anchors and a trailing external/next-page icon otherwise, using computed props rather than duplicated markup.

Scored August 1, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 29, 2026: 59/100. This rescore on v0.0.3: 59/100.

This page is an automated design review of vuetifyjs/vuetify’s UI code: 30 files read against 291 versioned rules covering accessibility, color, typography, spacing, components, UX, motion, and craft. The score is out of 100; confirmed criticals cap it — one at 59, two at 49, three or more at 39.

More design scores

Score your own repo.

Free on public repos, no account. The same engine that scored this page reads your UI code and mints a score page like this one.

Public repos only. The full engine reviews the UI code and mints a public score page — we email you the link too. Already-scored repos open instantly.

Or get a design review on every pull requestInstall Rams