appsmithorg on GitHub

appsmithorg/appsmith

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

30 files reviewed·August 1, 2026

View on GitHub

Elevated

Design risk in this codebase.

3issues
Critical & Serious

Top fix

Make page nav tabs real focusable elements, not divs

See the fix

Verdict

One component, StyledMenuItem, is responsible for both the critical keyboard-nav gap and the invisible active-state signal. EditorTabs proves the team can build accessible tabs with ADS primitives, so the fix is consistency, not invention.

Files Rams reviewed

app/client/src/pages/AppIDE/components/AppSettings/components/EmbedSettings/index.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/NavigationSettings/index.tsx

app/client/src/pages/AppIDE/components/PageList/ContextMenu/SetAsHomePage.tsx

app/client/src/pages/AppIDE/components/WidgetAdd/index.tsx

app/client/src/pages/AppIDE/layouts/components/EditorTabs/index.tsx

app/client/src/pages/AppIDE/layouts/components/Header/index.tsx

app/client/src/pages/AppViewer/Navigation/components/MenuItem/index.tsx

app/client/src/pages/Editor/gitSync/components/GitChangesList/index.tsx

app/client/src/ce/pages/AppIDE/components/AppIDEModals.tsx

app/client/src/ce/pages/AppIDE/components/QueryAdd/useGroupedAddQueryOperations.tsx

app/client/src/pages/AppIDE/components/AppPluginActionEditor/components/ContextMenuItems/ConvertToModule.tsx

app/client/src/pages/AppIDE/components/AppPluginActionEditor/components/ContextMenuItems/Copy.tsx

app/client/src/pages/AppIDE/components/AppPluginActionEditor/components/ContextMenuItems/CopyToApp.tsx

app/client/src/pages/AppIDE/components/AppPluginActionEditor/components/ContextMenuItems/Delete.tsx

app/client/src/pages/AppIDE/components/AppPluginActionEditor/components/ContextMenuItems/Move.tsx

app/client/src/pages/AppIDE/components/AppPluginActionEditor/components/ContextMenuItems/ShowBindings.tsx

app/client/src/pages/AppIDE/components/AppPluginActionEditor/components/ConvertToModule/ConvertToModuleCallout.tsx

app/client/src/pages/AppIDE/components/AppPluginActionEditor/components/ToolbarMenu/ToolbarMenu.tsx

app/client/src/pages/AppIDE/components/AppSettings/AppSettings.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/DraggablePageList.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/EmbedSettings/MakeApplicationForkable.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/ImportAppSettings.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/NavigationSettings/ButtonGroupSetting.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/NavigationSettings/ColorStyleIcon.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/NavigationSettings/ImageInput.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/NavigationSettings/LogoInput.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/NavigationSettings/SwitchSetting.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/NavigationSettings/SwitchSettingForLogoConfiguration.tsx

app/client/src/pages/AppIDE/components/AppSettings/components/StaticURLConfirmationModal.tsx

app/client/src/pages/AppIDE/components/GitModals.tsx

93/100

Accessibility

1 critical2 serious
AccessibilityCritical

app/client/src/pages/AppViewer/Navigation/components/MenuItem/index.tsx:63

Page nav tab is a div, so keyboard users can't switch pages

StyledMenuItem renders each page tab (class "t--page-switch-tab") as a styled div with onClick={handleClick} and no role, tabIndex, or key handler. MenuText inside carries the visible page name, but the clickable surface itself has no keyboard path.

Why it matters

A keyboard-only or switch-device user tabbing through the nav skips these entries entirely, since a div is never part of the tab order and has no Enter/Space activation. Page switching in this navigation becomes mouse-only for that user.

Fix

Render the tab as a native button (or add role="button", tabIndex={0}, and an onKeyDown handler for Enter/Space) so it lands in the natural tab order.

<StyledMenuItem
  borderRadius={borderRadius}
  className={`t--page-switch-tab ${isActive ? "is-active" : ""}`}
  navColorStyle={navColorStyle}
  onClick={handleClick}
  primaryColor={primaryColor}
>
  <MenuText
    name={page.pageName}
    navColorStyle={navColorStyle}
    primaryColor={primaryColor}
  />
</StyledMenuItem>
<StyledMenuItem
  as="button"
  type="button"
  borderRadius={borderRadius}
  className={`t--page-switch-tab ${isActive ? "is-active" : ""}`}
  navColorStyle={navColorStyle}
  onClick={handleClick}
  primaryColor={primaryColor}
>
  <MenuText
    name={page.pageName}
    navColorStyle={navColorStyle}
    primaryColor={primaryColor}
  />
</StyledMenuItem>
AccessibilitySerious

app/client/src/pages/AppIDE/layouts/components/EditorTabs/index.tsx:101

List-view toggle button has no accessible name for screen readers

EntityListButton in EditorTabs (data-testid="t--list-toggle") renders as an icon-only toggle wired to handleHamburgerClick, with isSelected controlling its state but no aria-label or visible text on the element.

Why it matters

A screen reader user landing on this control hears only "button" with no indication it opens the file list view, so they can't tell what activating it does without trial and error.

Fix

Add an aria-label describing the action (e.g. "Toggle file list view") and reflect state with aria-pressed={isListViewActive}.

<EntityListButton
  data-testid="t--list-toggle"
  isSelected={isListViewActive}
  onClick={handleHamburgerClick}
/>
<EntityListButton
  aria-label="Toggle file list view"
  aria-pressed={isListViewActive}
  data-testid="t--list-toggle"
  isSelected={isListViewActive}
  onClick={handleHamburgerClick}
/>
AccessibilitySerious

app/client/src/pages/AppViewer/Navigation/components/MenuItem/index.tsx:65

Active page tab signals selection with CSS class only, invisible to screen readers

The isActive state on each MenuItem is expressed purely through the "is-active" class in className={`t--page-switch-tab ${isActive ? "is-active" : ""}`}. No aria-current attribute is set on the element for the currently viewed page.

Why it matters

A screen reader user navigating the page tabs has no way to know which page is currently active, since class-name-only state is invisible to assistive tech. They lose orientation in a multi-page app.

Fix

Add aria-current={isActive ? "page" : undefined} to the tab element alongside the existing class toggle.

<StyledMenuItem
  borderRadius={borderRadius}
  className={`t--page-switch-tab ${isActive ? "is-active" : ""}`}
  navColorStyle={navColorStyle}
  onClick={handleClick}
  primaryColor={primaryColor}
>
<StyledMenuItem
  aria-current={isActive ? "page" : undefined}
  borderRadius={borderRadius}
  className={`t--page-switch-tab ${isActive ? "is-active" : ""}`}
  navColorStyle={navColorStyle}
  onClick={handleClick}
  primaryColor={primaryColor}
>

Typography

No issues found

Color

No issues found

Spacing

No issues found

Components

No issues found

Motion

No issues found

UX

No issues found

Craft

No issues found

Working well

  • Tab state in EditorTabs is driven through the ADS Tabs/TabsList/Tab/TabPanel primitives rather than a hand-rolled implementation, which keeps keyboard navigation and ARIA tab semantics correct without extra work.
  • handleTabClick and handleNewTabClick both dispatch setListViewActiveState(false) before switching context, keeping list view and tab view state from drifting out of sync as users move around the IDE.
  • isActive in MenuItem cleanly memoizes a static-URL vs legacy-URL branch with a tight dependency array, keeping routing logic readable instead of burying it in JSX.

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

This page is an automated design review of appsmithorg/appsmith’s UI code: 30 files read against 309 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