Skip to content

feat(core): add internal key binding service - #17789

Open
mddragnev wants to merge 16 commits into
masterfrom
mdragnev/key-bindings
Open

mddragnev wants to merge 16 commits into
masterfrom
mdragnev/key-bindings

Conversation

@mddragnev

@mddragnev mddragnev commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Closes #17753

Description

Adds an internal IgxKeyBindingsService, an Angular version of the addKeybindings controller from Ignite UI for Web Components, and moves the expansion panel header, date picker, date range picker, time picker and splitter bar to it.

Motivation / Context

The library has no shared keyboard layer. Each component mixes keydown.<key> host listeners, switch (event.key) handlers and PlatformUtil.KEYMAP checks. Each one also handles preventDefault, key repeats and keys from inner inputs in its own way, and some still check old IE key names. The service gives one declarative keyboard map per component, with the same defaults as Web Components.

The issue proposed a host directive. The PR uses a service that the component lists in its providers, so a component's keyboard map is registered in one place, in its constructor.

Ported components keep their existing behavior. The exceptions are deliberate fixes, all listed in the CHANGELOG.

Type of Change (check all that apply):

  • Bug fix
  • New functionality
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactoring (no functional changes)
  • Documentation
  • Demos
  • CI/CD
  • Tests
  • Changelog
  • Skills/Agents

Component(s) / Area(s) Affected:

How Has This Been Tested?

  • Unit tests
  • Manual testing
  • Automated e2e tests

Test Configuration:

  • Angular version:
  • Browser(s):
  • OS:

Screenshots / Recordings

Checklist:

  • All relevant tags have been applied to this PR
  • This PR includes unit tests covering all the new code (test guidelines)
  • This PR includes API docs for newly added methods/properties (api docs guidelines)
  • This PR includes feature/README.MD updates for the feature docs
  • This PR includes general feature table updates in the root README.MD
  • This PR includes CHANGELOG.MD updates for newly added functionality
  • This PR contains breaking changes
  • This PR includes ng update migrations for the breaking changes (migrations guidelines)
  • This PR includes behavioral changes and the feature specification has been updated with them
  • Accessibility (ARIA, keyboard navigation, focus management) has been verified

mddragnev and others added 14 commits October 16, 2026 17:35
- Release the held keys when focus leaves the host. A key released
  outside it, for example in an overlay, no longer stays held and
  matches a later combination, such as Alt alone opening a picker.
- An ignored repeated keydown still gets preventDefault and
  stopPropagation; only the handler is skipped, so a held key keeps
  its default action prevented.
Replace the Enter, Space and Alt + Arrow Up/Down host listeners with
IgxKeyBindingsService and drop the IE-only Spacebar key. Alt + Arrow
Up/Down no longer expand or collapse a disabled header.
Replace the keydown host listener with IgxKeyBindingsService. The keys
come from the inner inputs, so none are skipped. Alt + Arrow Up/Down
now prevent their default browser action.
Replace the keydown host listeners of the date picker and the calendar
container with IgxKeyBindingsService. Alt + Arrow Up/Down now prevent
their default browser action. The calendar container still stops
Alt + Arrow Up, so the picker does not close twice.
Replace the keydown host listeners of the time picker and its item
lists with IgxKeyBindingsService. Alt + Arrow Up/Down now prevent their
default browser action in drop-down mode and keep it in dialog mode.
Escape keeps its default action. Held arrows keep moving through the
items.
Remove the splitter bar from the tab order only when it can neither
resize nor collapse its panes, so a pane collapsed with Ctrl + arrow
can be expanded again from the keyboard. Ctrl + arrow no longer
collapses a pane when nonCollapsible is set. Add a resizable toggle to
the splitter sample.

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.

🟡 Changes recommended

Keyboard-state cleanup, modifier release handling, canceled interactions and API visibility remain unresolved.

4 open issues
What changed in this PR

Adds a shared keyboard-binding service to consolidate keyboard handling across Ignite UI components, addressing #17753.

Changes:

  • Introduces key constants, configurable bindings, listener cleanup and service tests.
  • Migrates picker, expansion-panel and splitter keyboard handling.
  • Updates splitter accessibility behavior, documentation and release notes.
File Description
projects/​igniteui-angular/​time-picker/​src/​time-picker/​time-picker.directives.ts Migrates time-list navigation.
projects/​igniteui-angular/​time-picker/​src/​time-picker/​time-picker.component.ts Registers picker shortcuts.
projects/​igniteui-angular/​time-picker/​src/​time-picker/​time-picker.component.spec.ts Tests shortcuts and held keys.
projects/​igniteui-angular/​splitter/​src/​splitter/​splitter.component.ts Migrates shortcuts and adjusts focusability.
projects/​igniteui-angular/​splitter/​src/​splitter/​splitter.component.spec.ts Tests resizing, collapsing and focus.
projects/​igniteui-angular/​splitter/​README.md Documents keyboard behavior.
projects/​igniteui-angular/​expansion-panel/​src/​expansion-panel/​expansion-panel.spec.ts Updates keyboard interaction tests.
projects/​igniteui-angular/​expansion-panel/​src/​expansion-panel/​expansion-panel-header.component.ts Registers header bindings.
projects/​igniteui-angular/​date-picker/​src/​date-range-picker/​date-range-picker.component.ts Registers range-picker shortcuts.
projects/​igniteui-angular/​date-picker/​src/​date-range-picker/​date-range-picker.component.spec.ts Tests shortcuts and focus transitions.
projects/​igniteui-angular/​date-picker/​src/​date-picker/​date-picker.component.ts Registers date-picker shortcuts.
projects/​igniteui-angular/​date-picker/​src/​date-picker/​date-picker.component.spec.ts Tests shortcut defaults and repeats.
projects/​igniteui-angular/​date-picker/​src/​date-picker/​calendar-container/​calendar-container.component.ts Migrates calendar-close shortcut.
projects/​igniteui-angular/​date-picker/​src/​date-picker/​calendar-container/​calendar-container.component.spec.ts Tests closing and propagation.
projects/​igniteui-angular/​core/​src/​public_api.ts Exports keyboard symbols.
projects/​igniteui-angular/​core/​src/​core/​key-bindings/​keys.ts Defines constants and key comparison.
projects/​igniteui-angular/​core/​src/​core/​key-bindings/​key-bindings.service.ts Implements shared keyboard handling.
projects/​igniteui-angular/​core/​src/​core/​key-bindings/​key-bindings.service.spec.ts Covers service behavior and lifecycle.
projects/​igniteui-angular/​core/​src/​core/​key-bindings.ts Aggregates keyboard exports.
CHANGELOG.md Records keyboard behavior changes.

Review effort: Balanced

Comment thread projects/igniteui-angular/core/src/core/key-bindings/key-bindings.service.ts Outdated
Comment thread projects/igniteui-angular/core/src/public_api.ts

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.

🔵 Needs a closer look

Unresolved keyboard-state and default-action regressions can trigger unintended shortcuts or suppress native control behavior.

No open issues 🎉

2 previously missed issues

In code that hasn't changed since last review

Medium severity Track pressed keys by physical code to handle shifted key releases

projects/​igniteui-angular/​core/​src/​core/​key-bindings/​key-bindings.service.ts:408

Tracking releases by event.key leaves shifted symbols stuck when Shift is released first. With a [shiftKey, '!'] binding on a US layout, press Shift+1, release Shift, then release 1: the last keyup reports 1, so deleting it leaves ! in _pressedKeys. Pressing Shift alone then invokes the shortcut without 1 being held. Record the keydown name by physical key identity (event.code) and release that stored name in both keyup paths, preserving support for events without a code. Add a regression test for this release order.

Medium severity Avoid preventing default for canceled Alt-arrow interactions

projects/​igniteui-angular/​expansion-panel/​src/​expansion-panel/​expansion-panel-header.component.ts:220

These Alt-arrow bindings still prevent the default before openPanel/closePanel checks interaction.cancel. A projected native select whose panel interaction is canceled therefore loses its native Alt+ArrowDown popup behavior; previously these handlers did not prevent the event. Disable automatic prevention here, as for Enter/Space, and cover canceled Alt-arrow interactions.

4 resolved since last review

Review effort: Balanced

@mddragnev
mddragnev requested a review from rkaraivanov October 21, 2026 13:50

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add an internal key bindings host directive (from webcomponents addKeybindings)

2 participants