appsmithorg/appsmith
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·August 1, 2026
More findings
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
Accessibility
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>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}
/>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
Color
Spacing
Components
Motion
UX
Craft
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.