Skip to content

ui: fix and improve panel UX and accessibility from the October 2026 audit #333

Closed as duplicate

Description

@erkamyaman

Context

This comes from a code audit of the panel's UX and accessibility (app/src), done in October 2026 while comparing the panel with other devtools (Nuxt DevTools, Vue DevTools and vite-plugin-inspect). It checks the panel against docs/contributing/ui-guidelines.md. Roadmap items live in #310, #311, #312 and #313. Items marked (to confirm) were not reproduced.

Problems

Medium

  • Error states without Retry: several error states tell the user to reload or reopen the panel and offer no button. Add a Retry button that calls the existing refresh() or load function, as pipes-inspector.ts:188-192 already does. In the shell, retry the devframe connection with backoff and show a "Reconnect" button (app/src/pages/network-inspector.ts:296-303, app/src/pages/dashboard.ts:234-241, app/src/app.ts:372-375).
  • Store has no loading state: before the first shared state arrives, the store page shows "No page is reporting NgRx state yet.", so NgRx users see a wrong message for a moment. Set a loaded flag on the first shared state value and show a role="status" "Loading…" state until then (app/src/pages/store-inspector.ts:130-143).
  • No arrow-key navigation in long lists: the network timeline (up to 2,000 rows), the store change and event lists and the signals node list need one Tab per row. Add roving tabindex with ArrowUp/Down and Home/End, like onListKey in pipes-inspector.ts:1341. A shared appRovingList directive would cover all of them (app/src/pages/network-inspector.ts:595-616, app/src/pages/store-inspector.ts:362, 499).

Low

  • Search fields differ from page to page: the guidelines ask for a search field with an icon, Escape to clear and a count. Only six pages have the search icon. It is missing on signal-inspector.ts:159, store-inspector.ts:100, forms-inspector.ts:358, route-tree.ts:115, route-timeline.ts:37 and route-inspector.ts:55. Placeholders mix "Filter" and "Find", and only some end with "…". Extract an <app-search-field> in app/src/ui with the icon, Escape, autocomplete="off", spellcheck="false" and an optional count, and pick one verb.
  • Route tree has no tree semantics: depth is shown only by padding-left, with no aria-level, aria-expanded or treegrid role, so screen readers lose the hierarchy. Use role="treegrid" with aria-level and aria-expanded, and support Left/Right to collapse and expand (app/src/pages/route-tree.ts:176-177).
  • Filtered lists tracked by $index: when the filter changes, rows are reused by position, so focus and selection jump. Track by a stable key such as route.file + route.fullPath, a finding's code and location, or a component id (app/src/pages/route-inspector.ts:118, route-current.ts:95, 167, route-lint.ts:65, forms-report.ts:162, cd-recording.ts:89).
  • Hex colors in the Analog view: the info and kind colors are hard-coded hex values outside the token system and the tint-contrast test. Move them to app/src/styles/_palette.scss or app/src/view-accents.ts with dark and light pairs, and add them to app/src/__tests__/tint-contrast.test.ts (app/src/pages/analog-inspector.ts:1133-1138, 1693-1725).
  • "Inspector turned off" gives no next step: the message names the inspectors key but has no docs link and no snippet. Add a link (as LimitNote does with LIMITS_DOCS_URL) and the exact option to turn it on, for example inspectors: { store: true } (app/src/app.ts:380-384).
  • No shortcut to focus search or switch tabs: there is no / to focus the current page's search and no key to switch tabs. Add a host listener in app.ts for / (expose each page's search through a small service) and Alt+1..9 for tabs, skipped while focus is in an input. The Cmd/Ctrl+K palette is tracked in phase 3 of 4: a devframe shell as good as Vue and Nuxt DevTools #312 (app/src/app.ts:149-153).

Improvements

  • One shared <app-state kind="loading|error|empty|no-match"> component with Retry and "Clear filters" slots, plus a spec that checks every page renders all four states (app/src/ui, app/src/pages/*.ts).
  • A spec that lists the pages and checks each one uses <app-search-field> and the roving-list directive (app/src/ui, app/src/pages/*.ts).
  • Resizable list and detail panes with a keyboard-accessible splitter (role="separator", aria-valuenow, arrow keys), width saved per view (app/src/pages/network-inspector.ts, store-inspector.ts, di-inspector.ts, app/src/tab-memory.ts).
  • "Pause live updates" and "Auto-scroll to newest" toggles on the network timeline, store change log and route timeline (app/src/pages/network-inspector.ts, store-inspector.ts, route-timeline.ts).
  • Sortable column headers with aria-sort on the network table (time, status, duration) and the route config table (app/src/pages/network-inspector.ts:580-592, app/src/pages/route-inspector.ts).
  • Saved filter chips per view, for example "Failed only" and "SSR" on the network page, stored in localStorage inside try/catch (app/src/pages/network-inspector.ts, app/src/tab-memory.ts).
  • Run pnpm test:axe on the loading, error and no-match states too, not only the populated static report.

Already tracked elsewhere

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or shows wrong datafeatureA feature request or a pull request that adds one

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions