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

hoppscotch/hoppscotch

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.

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

Top fix

Add keyboard access and ARIA roles to icon-only interactive elements

See the fix

Verdict

Power-user density without the accessibility scaffolding to support it, icon triggers, hidden divs, and custom menus all skip basic semantics. The biggest risk is a broken keyboard shortcut that throws on click, right where speed matters most.

Files Rams reviewed

packages/hoppscotch-common/src/components/app/ActionHandler.vue

packages/hoppscotch-common/src/components/app/Banner.vue

packages/hoppscotch-common/src/components/app/ContextMenu.vue

packages/hoppscotch-common/src/components/app/DeveloperOptions.vue

packages/hoppscotch-common/src/components/app/Footer.vue

packages/hoppscotch-common/src/components/app/Inspection.vue

packages/hoppscotch-common/src/components/app/KernelInterceptor.vue

packages/hoppscotch-common/src/components/app/Logo.vue

packages/hoppscotch-common/src/components/app/Options.vue

packages/hoppscotch-common/src/components/app/PaneLayout.vue

packages/hoppscotch-common/src/components/app/Share.vue

packages/hoppscotch-common/src/components/app/Shortcuts.vue

packages/hoppscotch-common/src/components/app/ShortcutsPrompt.vue

packages/hoppscotch-common/src/components/app/Sidenav.vue

packages/hoppscotch-common/src/components/app/Support.vue

packages/hoppscotch-common/src/components/app/WhatsNewDialog.vue

packages/hoppscotch-common/src/components/app/spotlight/Entry.vue

packages/hoppscotch-common/src/components/app/spotlight/entry/GQLRequest.vue

packages/hoppscotch-common/src/components/app/spotlight/entry/RESTHistory.vue

packages/hoppscotch-common/src/components/app/spotlight/entry/RESTRequest.vue

packages/hoppscotch-common/src/components/app/spotlight/index.vue

packages/hoppscotch-sh-admin/src/components/app/Header.vue

packages/hoppscotch-sh-admin/src/components/app/Login.vue

packages/hoppscotch-sh-admin/src/components/app/Logout.vue

packages/hoppscotch-sh-admin/src/components/app/Modal.vue

packages/hoppscotch-sh-admin/src/components/app/Sidebar.vue

packages/hoppscotch-common/src/components/app/GitHubStarButton.vue

packages/hoppscotch-common/src/components/app/Markdown.vue

packages/hoppscotch-common/src/components/app/ShortcutsEntry.vue

packages/hoppscotch-common/src/components/app/SpotlightSearch.vue

88/100

Accessibility

4 critical
AccessibilityCritical

packages/hoppscotch-common/src/components/app/Footer.vue:131

Developer options only reachable via double-click on a plain div

The version label in Footer.vue is a plain `<div class="flex px-4 py-2 opacity-50" @dblclick="...showDeveloperOptionModal()...">`, with no `role`, `tabindex`, or keyboard handler.

Why it matters

A keyboard-only user can never trigger developer options since the div has no focus stop and no key event, locking that entry point out entirely for non-mouse users.

Fix

Convert the trigger to a real `<button>` (or add `tabindex="0"`, `role="button"`, and a keydown handler) so it's reachable and operable by keyboard.

<div
                class="flex px-4 py-2 opacity-50"
                @dblclick="
                  () => {
                    showDeveloperOptionModal()
                    hide()
                  }
                "
              >
                {{ `${t("app.name")} v${version}` }}
              </div>
<button
                type="button"
                class="flex px-4 py-2 opacity-50"
                @dblclick="
                  () => {
                    showDeveloperOptionModal()
                    hide()
                  }
                "
              >
                {{ `${t("app.name")} v${version}` }}
              </button>
AccessibilityCritical

packages/hoppscotch-common/src/components/app/Banner.vue:18

Banner dismiss icon has no keyboard path or accessible name

The dismiss control in Banner.vue is an `icon-lucide-x` with a raw `@click="emit('dismiss')"`, not a `<button>`. It carries no `role`, no `tabindex`, and no `aria-label`, so keyboard users can't tab to it and screen reader users hear nothing when it's announced.

Why it matters

A user who navigates by keyboard or screen reader cannot dismiss this banner at all, so it stays on screen and blocks the layout below it indefinitely for that user.

Fix

Wrap the dismiss icon in a real `<button>` with an `aria-label` so it gets native keyboard focus and a screen-reader name for free.

<icon-lucide-x
      v-if="banner.dismissible"
      class="opacity-50 hover:cursor-pointer hover:opacity-100"
      @click="emit('dismiss')"
    />
<button
      v-if="banner.dismissible"
      type="button"
      :aria-label="t('action.dismiss')"
      class="opacity-50 hover:cursor-pointer hover:opacity-100"
      @click="emit('dismiss')"
    >
      <icon-lucide-x />
    </button>
AccessibilityCritical

packages/hoppscotch-common/src/components/app/Inspection.vue:6

Icon-only inspection trigger has no accessible name

The `HoppButtonSecondary` in Inspection.vue that opens the inspections popover renders `:icon="IconAlertTriangle"` with only a `v-tippy` hover tooltip and a `:title` attribute, no visible label and no `aria-label`.

Why it matters

A screen reader user tabbing to this button hears nothing describing what it does, so they can't discover or open the inspections panel at all.

Fix

Add an explicit `aria-label` bound to the same translation string used for the tooltip so the button has a real accessible name independent of hover state.

<HoppButtonSecondary
          v-tippy="{ theme: 'tooltip' }"
          :icon="IconAlertTriangle"
          :class="severityColor(getHighestSeverity.severity)"
          :title="t('inspections.description')"
        />
<HoppButtonSecondary
          v-tippy="{ theme: 'tooltip' }"
          :icon="IconAlertTriangle"
          :class="severityColor(getHighestSeverity.severity)"
          :title="t('inspections.description')"
          :aria-label="t('inspections.description')"
        />
AccessibilityCritical

packages/hoppscotch-common/src/components/app/ContextMenu.vue:2

Context menu has no menu role, no Escape key, no focus entry

The root `<div ref="contextMenuRef">` in ContextMenu.vue renders `HoppSmartItem` options with click handlers, but the container has no `role="menu"`, no keydown handler for Escape, and nothing moves focus into it when it opens.

Why it matters

A keyboard-only user who opens this context menu has no way to close it or move between its options with the keyboard, and a screen reader gives no indication a menu opened at all.

Fix

Give the container `role="menu"`, move focus to the first item on open, and add an Escape handler that closes it and returns focus to the trigger.

<div
    ref="contextMenuRef"
    class="fixed transform -translate-x-10 -translate-y-8 rounded border border-dividerDark bg-popover p-2 shadow-lg"
    :style="`top: ${position.top}px; left: ${position.left}px; z-index: 100;`"
  >
<div
    ref="contextMenuRef"
    role="menu"
    tabindex="-1"
    class="fixed transform -translate-x-10 -translate-y-8 rounded border border-dividerDark bg-popover p-2 shadow-lg"
    :style="`top: ${position.top}px; left: ${position.left}px; z-index: 100;`"
    @keydown.esc="closeMenu"
  >
98/100

UX

1 serious
UXSerious

packages/hoppscotch-common/src/components/app/Footer.vue:157

Footer 'c' shortcut calls click on an undefined chat ref and throws

Footer.vue binds `@keyup.c="chat!.$el.click()"`, but no element in the template carries `ref="chat"`, so `chat` is `undefined` and the non-null assertion `chat!` throws at runtime the moment a user presses 'c'.

Why it matters

Any user who presses 'c' while the footer is focused hits a JS error instead of the intended chat action, breaking the shortcut and potentially the surrounding interaction.

Fix

Guard the call with optional chaining so a missing ref fails silently instead of throwing, and attach the missing ref to its intended element.

@keyup.c="chat!.$el.click()"
@keyup.c="chat?.$el?.click()"

Get this score on every PR.

Rams reviews each pull request on your repo and posts inline one-click fixes — about a minute per review.

Install Rams free
98/100

Craft

1 serious
CraftSerious

packages/hoppscotch-common/src/components/app/ContextMenu.vue:6

Context menu z-index is hardcoded outside any layering scale

ContextMenu.vue sets `z-index: 100` directly inside an inline `:style` string on the root div, rather than through a shared stacking token.

Why it matters

A hardcoded z-index competing with modals, toasts, or tooltips defined elsewhere in the app leads to menus getting hidden behind or on top of the wrong surface, and each fix becomes a guess-and-check across files.

Fix

Move the z-index into the class list using an existing stacking utility or design-system z-index token instead of an inline literal.

:style="`top: ${position.top}px; left: ${position.left}px; z-index: 100;`"
:style="`top: ${position.top}px; left: ${position.left}px;`"
    class="fixed z-menu transform -translate-x-10 -translate-y-8 rounded border border-dividerDark bg-popover p-2 shadow-lg"

Typography

No issues found

Color

No issues found

Spacing

No issues found

Components

No issues found

Motion

No issues found

Working well

  • Arrow-key navigation (onArrowUp/onArrowDown) wraps correctly across section boundaries and resets to [0,0] on new search, giving keyboard users full parity with mouse hover selection.
  • bannerRole correctly maps error banners to role="alert" and info/warning to role="status", giving screen reader users appropriate interruption levels per banner type.
  • The copy button correctly swaps icon state via refAutoReset with a 1000ms reset, giving clear temporary visual confirmation without extra state management.
  • The sidebar-toggle icon buttons rotate their icon in sync with state (`-rotate-180` when collapsed) which gives a clear visual cue of the toggle direction.

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

This page is an automated design review of hoppscotch/hoppscotch’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