feat(file-browser): keyboard and screen-reader accessibility for mo.ui.file_browser#10005
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
3 issues found across 2 files
Architecture diagram
sequenceDiagram
participant User as User
participant FB as FileBrowser Component
participant RowModel as rowModel[]
participant RefArr as rowRefs[]
participant DOM as Browser DOM
participant Backend as Backend API
Note over FB: Component mount / path change
FB->>Backend: list_directory(path)
Backend-->>FB: files[]
FB->>FB: Build rowModel[] from files<br/>(each row: key, name, icon,<br/>canSelect, onPrimary, onToggleSelect)
FB->>FB: setActiveIndex(0)
FB->>FB: Render table with role="grid",<br/>aria-multiselectable,<br/>row.role="row", tabIndex per activeIndex
Note over User,DOM: User moves into the grid (Tab)
User->>DOM: Tab into grid
DOM-->>FB: focus on first row (activeIndex=0)
Note over User,DOM: Keyboard navigation
User->>DOM: ArrowDown key
DOM-->>FB: onKeyDown(e, index)
FB->>FB: handleRowKeyDown(index)
alt ArrowDown
FB->>FB: focusRow(index+1)
FB->>FB: setActiveIndex(index+1)
FB->>RefArr: refs[index+1].focus()
RefArr-->>DOM: focus row
else ArrowUp
FB->>FB: focusRow(index-1)
FB->>FB: setActiveIndex(index-1)
FB->>RefArr: refs[index-1].focus()
else Home
FB->>FB: focusRow(0)
FB->>FB: setActiveIndex(0)
FB->>RefArr: refs[0].focus()
else End
FB->>FB: focusRow(lastIndex)
FB->>FB: setActiveIndex(lastIndex)
FB->>RefArr: refs[lastIndex].focus()
end
Note over User,DOM: Primary action (Enter) and toggle (Space)
User->>DOM: Enter key
DOM-->>FB: onKeyDown
FB->>FB: handleRowKeyDown
alt Enter
FB->>RowModel: rowModel[index].onPrimary()
RowModel-->>FB: e.g., navigate into directory or toggle selection
opt If directory navigation
FB->>Backend: list_directory(newPath)
Backend-->>FB: new files[]
FB->>FB: Build new rowModel[]
FB->>FB: setActiveIndex(0)
end
else Space
FB->>RowModel: rowModel[index].onToggleSelect?.()
RowModel-->>FB: toggle selection, update value
end
Note over User,DOM: ARIA updates
FB->>DOM: Update aria-selected on rows,<br/>checkbox accessibility label
DOM-->>User: Screen reader announces changes
Note over FB: Non-selectable file click fixed
User->>FB: Click on non-selectable file<br/>(selection_mode="directory")
FB->>FB: Calls rowModel[index].onPrimary()<br/>(which is no-op for non-selectable files)
FB-->>User: No selection changed
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves mo.ui.file_browser accessibility by implementing a roving-tabindex, row-focused ARIA grid interaction model so the file list becomes fully keyboard- and screen-reader-operable, while also aligning mouse/keyboard behavior for non-selectable rows.
Changes:
- Reworks the file list into a unified row model with per-row primary (Enter/click) and select-toggle (Space) actions.
- Adds ARIA grid/row/gridcell roles, checkbox labeling, and keeps checkboxes out of the tab order.
- Adds a new test suite covering roles/labels, roving tabindex behavior, keyboard matrix, and the non-selectable click fix.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| frontend/src/plugins/impl/FileBrowserPlugin.tsx | Implements ARIA grid semantics, roving tabindex, and unified row action handling for keyboard + mouse. |
| frontend/src/plugins/impl/tests/FileBrowserPlugin.test.tsx | Adds accessibility and interaction tests for the new grid/keyboard behavior. |
Give the grid an accessible name, reset and follow focus to the parent row when the listing reloads (including same-path refreshes), and sync the active row to whatever gains focus so the only tabbable row always matches the focused element.
akshayka
approved these changes
Jun 26, 2026
|
🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.23.12-dev8 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📝 Summary
Make
mo.ui.file_browserfully keyboard- and screen-reader-operable by adopting the WAI-ARIA single-column row-focus grid pattern on the existing table. The row list (the parent..row plus each file and directory) becomes one uniform model where every row carries its own primary action (Enter/click) and toggle-select action (Space).Roving tabindex makes the list a single tab stop: Tab moves into the list and back out rather than walking every row. The active row resets to
..whenever the directory listing changes.Keyboard navigation
Tab↑/↓Home/EndEnterSpaceEnter and Space resolve per row type:
Enter(primary)Space(select)..(parent)For assistive tech, the table exposes
role="grid"/row/gridcellwitharia-multiselectable, selectable rows exposearia-selected, and each checkbox is labeledSelect <name>, kept out of the tab order, and revealed on row focus as well as hover.This also fixes a latent inconsistency: a mouse click on a non-selectable file (for example a file in
selection_mode="directory") previously still added it to the value. Routing mouse and keyboard through one per-row primary action makes a non-selectable file inert for both, matching the matrix above.No backend or shared-component changes: all edits are in
FileBrowserPlugin.tsx, plus a new test file covering roles, labels, roving tabindex, focus reset, the key matrix, and the click fix.Closes MO-5937