Skip to content

[scheduler] Allow creating events via keyboard - EventCalendar#21967

Open
rita-codes wants to merge 16 commits intomui:masterfrom
rita-codes:21927-scheduler-allow-creating-events-via-keyboard
Open

[scheduler] Allow creating events via keyboard - EventCalendar#21967
rita-codes wants to merge 16 commits intomui:masterfrom
rita-codes:21927-scheduler-allow-creating-events-via-keyboard

Conversation

@rita-codes
Copy link
Copy Markdown
Member

Issue #21927

@rita-codes rita-codes self-assigned this Apr 2, 2026
@rita-codes rita-codes added type: new feature Expand the scope of the product to solve a new problem. scope: scheduler Changes related to the scheduler. labels Apr 2, 2026
@mui-bot
Copy link
Copy Markdown

mui-bot commented Apr 2, 2026

Deploy preview: https://deploy-preview-21967--material-ui-x.netlify.app/

Bundle size report

Bundle Parsed size Gzip size
@mui/x-data-grid 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-pro 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-premium 0B(0.00%) 0B(0.00%)
@mui/x-charts 0B(0.00%) 0B(0.00%)
@mui/x-charts-pro 0B(0.00%) 0B(0.00%)
@mui/x-charts-premium 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers-pro 0B(0.00%) 0B(0.00%)
@mui/x-tree-view 0B(0.00%) 0B(0.00%)
@mui/x-tree-view-pro 0B(0.00%) 0B(0.00%)

Details of bundle changes

Generated by 🚫 dangerJS against 594f253

@rita-codes rita-codes marked this pull request as ready for review April 2, 2026 16:02
Copy link
Copy Markdown
Member

@flaviendelangle flaviendelangle left a comment

Choose a reason for hiding this comment

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

PR Review Summary: #21967

[scheduler] Allow creating events via keyboard - EventCalendar

Critical Issues (2 found)

  1. ArrowRight has no upper-bound check — focus silently lost
    getNavigationTarget.ts:19ArrowLeft guards columnIndex > 0, but ArrowRight unconditionally returns columnIndex + 1. When pressed on the last column, setFocusedCell stores an out-of-range index, no cell matches hasFocus, and the roving tabindex breaks — focus disappears with no feedback.

    Fix: Pass columnCount into the function and guard: return columnIndex < columnCount - 1 ? { rowType, columnIndex: columnIndex + 1 } : null;

  2. ArrowDown/ArrowUp navigate to row types that may not be rendered
    getNavigationTarget.ts:6ROW_ORDER is hardcoded as ['header', 'day-grid', 'time-grid']. Not all views render all three row types (e.g., month view may lack time-grid). Navigating to a non-existent row silently loses focus.

    Fix: Make ROW_ORDER dynamic (derived from which rows are actually rendered), or validate coordinates before applying focus.

Important Issues (2 found)

  1. CalendarGridHeaderCell starts with tabIndex: -1, unreachable via Tab
    CalendarGridHeaderCell.tsx uses tabIndex: hasFocus ? 0 : -1, while DayCell and TimeColumn use tabIndex: focusedCell === null || hasFocus ? 0 : -1. In the initial state (focusedCell === null), all header cells get tabIndex=-1 and are completely unreachable by Tab. This is inconsistent and likely a bug.

    Fix: Use the same pattern: tabIndex: focusedCell === null || hasFocus ? 0 : -1

  2. handleFocus in CalendarGridHeaderCell missing child-event guard
    DayCell and TimeColumn check event.target === event.currentTarget before calling setFocusedCell. The header cell's handleFocus lacks this guard, so focus events bubbling from child buttons will incorrectly trigger setFocusedCell.

    Fix: Add if (event.target === event.currentTarget) guard.

Test Coverage Gaps (3 found)

  1. No unit tests for getNavigationTarget.ts (Criticality: 9/10) — This pure function contains all navigation logic and is the ideal candidate for thorough unit testing. All boundary conditions (ArrowLeft at 0, ArrowUp from header, row transitions, non-arrow keys) should be covered.

  2. No tests for CalendarGridHeaderCell keyboard behavior (Criticality: 8/10) — The header cell has unique Enter-delegates-to-button behavior that is completely untested.

  3. No tests for arrow key navigation between cells (Criticality: 7/10) — The headline feature (arrow key movement) has zero test coverage. Only Enter-key creation is tested.

Type Design Suggestions (3 found)

  1. GridCellRowType overlaps with EventSurfaceType — Consider extracting shared members:

    type GridSurfaceType = 'day-grid' | 'time-grid';
    type GridCellRowType = 'header' | GridSurfaceType;
    type EventSurfaceType = GridSurfaceType | 'timeline';
  2. setFocusedCell cannot reset to null — No public API to clear focus when it leaves the grid. Worth documenting whether this is intentional.

  3. Add satisfies GridCellRowType[] to ROW_ORDER so TypeScript catches invalid entries if the union changes.

Strengths

  • Clean separation of keyboard creation (useKeyboardEventCreation) from mouse creation (useEventCreation)
  • getNavigationTarget is properly extracted as a pure utility — excellent for testability
  • Consistent event.target === event.currentTarget guards in DayCell and TimeColumn handlers
  • Well-structured tests with proper provider wrappers and both positive/negative cases
  • Good use of null initial state for roving tabindex first-render behavior
  • No error suppression — errors propagate naturally through React boundaries
  • CreationPlaceholderFields type is well-designed with clean Omit pattern

Recommended Action

  1. Must fix: Add upper-bound check for ArrowRight in getNavigationTarget
  2. Must fix: Align CalendarGridHeaderCell tabIndex/focus patterns with the other cells
  3. Should fix: Add unit tests for getNavigationTarget (pure function, easy to test)
  4. Should fix: Handle non-existent row types in vertical navigation
  5. Consider: Tests for arrow key navigation and header cell keyboard behavior
  6. Consider: Extract shared keyboard navigation logic into a reusable hook to reduce duplication across the 3 cell components

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

Labels

accessibility a11y scope: scheduler Changes related to the scheduler. type: new feature Expand the scope of the product to solve a new problem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants