| Data integrity |
A send, an edit, a mode switch, or a saved draft never drops text, formatting, or media. A failed send keeps its text for another try, and never posts twice. The one exception is a draft upload that the daily cleanup removed, and its tile says it expired. |
Common practice in chat products |
| What you see is what you send |
The composer offers only formatting that the sent message keeps. An edit with no text and no attachment left never offers a send that must fail. |
Common practice in rich text chat |
| First message |
The first message or comment on a heading with no channel row creates the row and sends. |
Common practice in chat products |
| Voice notes |
Release ends a hold. A slide cancels or locks. The composer's 5-minute cap stops a long note. |
Slide to cancel and slide to lock follow Telegram and WhatsApp. There, release sends the note. Here, release shows a preview, as #265 asks. The cap is the composer's own limit. |
| Keyboard |
Escape closes one layer at a time. |
WAI-ARIA Authoring Practices, combobox and dialog patterns |
| Overlays |
One composer overlay is open at a time. The link dialog leaves the soft keyboard as it found it, except where #285 changes the rule on purpose. |
The chatroom and extensions agent docs |
| Focus |
No positive tabindex, and focus follows the visual order. A chat open that asks for focus gets it. |
WCAG 2.2, success criterion 2.4.3 |
| Names, roles, and states |
Every control has an accessible name. A toggle exposes its state. Menus, lists, and handles work with a keyboard. Live regions do not repeat. |
WCAG 2.2, success criteria 4.1.2 and 4.1.3, and the WAI-ARIA Authoring Practices |
| Toolbar state |
A format button shows its active state as the caret moves. |
Common practice in rich text toolbars |
| Touch targets |
The composer row buttons and every control that #279 lists have a touch target of at least 44 × 44 px on a phone. |
The design system ComposerBar row: "action targets 44px mobile". WCAG 2.2, success criterion 2.5.8, sets 24 px as the floor. |
| File limits |
A file over the size limit that the composer does not downscale is refused when it is added. A size failure offers no Retry. |
Common practice in chat products |
| Layout and loading |
A skeleton has the size of what replaces it, and never stays next to an error. A signed-in member sees the composer, not a join prompt. |
Core Web Vitals, Cumulative Layout Shift |
| Notifications |
A mention notifies the named member, and an email address mentions nobody. |
Common practice in chat products |
| Verification |
Chat flows run in CI, and a failing chat spec fails its job. |
Common practice |
| Code health and docs |
No dead code except what the house rules keep, and SignInToJoinChannel, which #274 leaves for a separate decision. No any in the chat store fields and broadcast payloads that #272 lists. No leaked listeners, no needless re-renders, and agent docs that match the code. |
AGENTS.md §Code Quality and §Workflow And Review Expectations. No house rule bans any in general, and the shared ESLint config turns @typescript-eslint/no-explicit-any off. This review sets that part. |
Purpose
This issue tracks the chat composer review of 2026-09-13. It lists every issue that the review filed, and one earlier issue, #263. It also holds one flag. The flag says whether the composer meets the standard in the table below.
The flag
Flag: red.
Update the flag when an issue closes. Move to amber only when every issue in the red list is closed.
The standard
tabindex, and focus follows the visual order. A chat open that asks for focus gets it.SignInToJoinChannel, which #274 leaves for a separate decision. Noanyin the chat store fields and broadcast payloads that #272 lists. No leaked listeners, no needless re-renders, and agent docs that match the code.anyin general, and the shared ESLint config turns@typescript-eslint/no-explicit-anyoff. This review sets that part.Issues
Red list: data loss or a broken core flow
Amber list: other user-facing issues, and the CI job
Code health and docs
Earlier issue
#263 is not a review finding. It fixes the
send-and-retryspec, and #276 lands after it. #266, #281, and #290 change the same early clear.How the review worked
14ab7f9c1. The two later commits change only files for the hypermultimedia README images.