Skip to content

feat(app): clearer interactive question card#1643

Open
cleiter wants to merge 2 commits into
getpaseo:mainfrom
cleiter:interactive-question-text
Open

feat(app): clearer interactive question card#1643
cleiter wants to merge 2 commits into
getpaseo:mainfrom
cleiter:interactive-question-text

Conversation

@cleiter

@cleiter cleiter commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Linked issue

Closes #1642

Type of change

  • New feature (with prior issue + design alignment)

What does this PR do

Brings the interactive question card (AskUserQuestion) closer to the Claude Code CLI's clarity, all in one component (packages/app/src/components/question-form-card.tsx):

  • Legible typography — option labels 16px semibold, descriptions 14px, matching the surrounding conversation instead of receding below it (they were 14px/12px).
  • Discoverable multi-select — a static left-side control (square checkbox for multi-select, radio circle for single-select), always visible. Replaces a trailing check that only appeared on selection and reflowed the row.
  • Titled multi-question nav — each question's header renders as a tab (with a check on answered ones) instead of a bare numbered circle, so you can see what each step is. Hidden for a single-question card.
  • a11y — single-select options grouped in a radiogroup; per-row checkbox/radio roles; aria-selectedaria-checked (the correct state for these roles).

No protocol/schema change — multiSelect was already parsed on the client. Also updates the e2e question helper (e2e/helpers/questions.ts) for the new option roles.

How did you verify it

  • npm run typecheck, npm run lint, npm run format — clean.
  • npx playwright test e2e/question-prompt-pagination.spec.ts — passes (exercises the new option roles + the updated helper).
  • Before/after screenshots are in feat: clearer interactive question card — legibility, discoverable multi-select, titled nav #1642 — covering typography, the multi-select affordance, the titled nav, and the answered state (selected checkbox fills + a ✓ on the tab). Generated by driving the mock provider through the real card on web with Playwright, toggling only this component between base and change (before = left, after = right).

Web shown. It's a shared RN component, so iOS/Android/desktop render the same tree — happy to add native captures if you want them.

Checklist

Bring the AskUserQuestion card closer to the Claude Code CLI's clarity:

- Legible typography: option labels 16px semibold, descriptions 14px,
  matching the surrounding conversation instead of receding below it.
- Discoverable multi-select: a static left-side control (checkbox for
  multi-select, radio for single-select) replaces a trailing check that
  only appeared on selection and reflowed the row.
- Multi-question nav shows each question's title, with a check on answered
  ones, instead of bare numbered circles.
- a11y: single-select options grouped in a radiogroup; per-row
  checkbox/radio roles; aria-selected -> aria-checked.

Updates the e2e question helper for the new option roles. No protocol
change; multiSelect was already parsed on the client.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jun 21, 2026

Copy link
Copy Markdown

Greptile Summary

This PR refines the AskUserQuestion card with clearer typography (16px semibold labels, 14px descriptions), always-visible selection controls (checkbox square vs. radio circle), titled multi-question nav tabs, and correct ARIA semantics (radio/checkbox roles with aria-checked, a radiogroup wrapper for single-select, and tab/tablist for the nav).

  • Option rows now carry the right accessibilityRole (radio/checkbox) and accessibilityState.checked, replacing the former button/aria-selected combination.
  • QuestionNav is extracted as its own component; it returns null for a single question and renders a tablist for multi-question flows, with per-tab answered indicators.
  • E2E helpers are updated to query options by their correct ARIA roles and to skip the nav assertion for single-question cards.

Confidence Score: 5/5

Safe to merge — the change is contained to one UI component and its E2E helpers, with no protocol or schema changes.

All changes are scoped to a single presentational component and its test helpers. The core logic (selection state, answer building, question parsing) is untouched. The ARIA corrections are improvements over the prior code, and the visual/layout changes are additive. The one oversight — the nav tab's accessibilityLabel shadowing the visible header for screen readers — is a quality concern but not a functional regression.

packages/app/src/components/question-form-card.tsx — the QuestionNavButton accessible label.

Important Files Changed

Filename Overview
packages/app/src/components/question-form-card.tsx UI/a11y overhaul: correct checkbox/radio roles and aria-checked for options, new always-visible selection controls, and a QuestionNav component that shows titled tabs (hidden for single questions). Accessible name for nav tabs overrides the visible header text, partially counteracting the a11y goals.
packages/app/e2e/helpers/questions.ts Helper updated to use radio/checkbox roles and aria-checked for option assertions, and a tab role for nav; includes a guard that skips the nav assertion for single-question cards (noted in prior review comments).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[QuestionFormCard] --> B{questions.length <= 1?}
    B -- yes --> C[No nav rendered]
    B -- no --> D[QuestionNav tablist]
    D --> E[QuestionNavButton x N
role=tab, aria-selected]
    A --> F[questionHeader
active question text]
    A --> G{activeQuestion.multiSelect?}
    G -- yes --> H[optionsWrap
no role wrapper]
    G -- no --> I[optionsWrap
role=radiogroup]
    H --> J[QuestionOptionRow
role=checkbox
accessibilityState.checked]
    I --> K[QuestionOptionRow
role=radio
accessibilityState.checked]
    J --> L[selectionControl square
filled when checked]
    K --> M[selectionControl circle
radio dot when selected]
    A --> N[Actions row
Dismiss + Next/Submit]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[QuestionFormCard] --> B{questions.length <= 1?}
    B -- yes --> C[No nav rendered]
    B -- no --> D[QuestionNav tablist]
    D --> E[QuestionNavButton x N
role=tab, aria-selected]
    A --> F[questionHeader
active question text]
    A --> G{activeQuestion.multiSelect?}
    G -- yes --> H[optionsWrap
no role wrapper]
    G -- no --> I[optionsWrap
role=radiogroup]
    H --> J[QuestionOptionRow
role=checkbox
accessibilityState.checked]
    I --> K[QuestionOptionRow
role=radio
accessibilityState.checked]
    J --> L[selectionControl square
filled when checked]
    K --> M[selectionControl circle
radio dot when selected]
    A --> N[Actions row
Dismiss + Next/Submit]
Loading

Reviews (2): Last reviewed commit: "fix(app): model question nav as a tablis..." | Re-trigger Greptile

Addresses review feedback on getpaseo#1643:

- The nav tabs were role="button" + aria-selected, which is invalid ARIA
  (aria-selected isn't defined for the button role). Model the nav as
  role="tablist" containing role="tab" items, which makes aria-selected
  valid and is semantically accurate for a question switcher.
- Guard expectCurrentQuestion's nav assertion so it only runs for
  multi-question cards — the nav is hidden for a lone question, so the
  helper would otherwise time out if used on a single-question flow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cleiter

cleiter commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Addressed Greptile feedback in 34f1025:

  • Modeled the question nav as role="tablist" containing role="tab" items, so aria-selected is valid ARIA (and accurate semantics for a question switcher) rather than being set on a role="button".
  • Guarded expectCurrentQuestion so it only asserts the nav tab for multi-question cards — the nav is hidden for a lone question, so the helper is now safe for single-question flows instead of timing out.

Pagination e2e re-run green against the new roles.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: clearer interactive question card — legibility, discoverable multi-select, titled nav

1 participant