Skip to content

feat(file-browser): keyboard and screen-reader accessibility for mo.ui.file_browser#10005

Merged
kirangadhave merged 6 commits into
mainfrom
kg/file-browser-keyboard-a11y
Jun 26, 2026
Merged

feat(file-browser): keyboard and screen-reader accessibility for mo.ui.file_browser#10005
kirangadhave merged 6 commits into
mainfrom
kg/file-browser-keyboard-a11y

Conversation

@kirangadhave

@kirangadhave kirangadhave commented Jun 26, 2026

Copy link
Copy Markdown
Member

📝 Summary

Make mo.ui.file_browser fully 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

Key Action
Tab Move into / out of the list (one tab stop for the whole grid)
/ Move focus one row; clamps at the ends, no wrap
Home / End Jump to the first / last row
Enter Run the row's primary action (mirrors a mouse click)
Space Toggle selection only; never navigates

Enter and Space resolve per row type:

Row Enter (primary) Space (select)
.. (parent) Navigate up no-op
Directory, selectable (mode = directory/all) Navigate into Toggle selection
Directory, not selectable (mode = file) Navigate into no-op
File, selectable (mode = file/all) Toggle selection Toggle selection
File, not selectable (mode = directory) no-op no-op

For assistive tech, the table exposes role="grid"/row/gridcell with aria-multiselectable, selectable rows expose aria-selected, and each checkbox is labeled Select <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

Review in cubic

@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Jun 26, 2026 8:16pm

Request Review

@kirangadhave kirangadhave marked this pull request as ready for review June 26, 2026 19:47
Copilot AI review requested due to automatic review settings June 26, 2026 19:47
@kirangadhave kirangadhave added the enhancement New feature or request label Jun 26, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread frontend/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx
Comment thread frontend/src/plugins/impl/FileBrowserPlugin.tsx
Comment thread frontend/src/plugins/impl/FileBrowserPlugin.tsx Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread frontend/src/plugins/impl/FileBrowserPlugin.tsx Outdated
Comment thread frontend/src/plugins/impl/FileBrowserPlugin.tsx
Comment thread frontend/src/plugins/impl/FileBrowserPlugin.tsx
Comment thread frontend/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx
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.
@kirangadhave kirangadhave merged commit a809291 into main Jun 26, 2026
31 checks passed
@kirangadhave kirangadhave deleted the kg/file-browser-keyboard-a11y branch June 26, 2026 20:36
@github-actions

Copy link
Copy Markdown

🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.23.12-dev8

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants