Skip to content

feat(date-picker): align with fusion DS - #8067

Closed
ibutakova wants to merge 2 commits into
masterfrom
FE-7142-date-picker-accessibility
Closed

feat(date-picker): align with fusion DS#8067
ibutakova wants to merge 2 commits into
masterfrom
FE-7142-date-picker-accessibility

Conversation

@ibutakova

@ibutakova ibutakova commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Proposed behaviour

Aligns DatePicker component component with fusion DS designs and accessibility requirements:

  • creates "typical" renderer for DatePicker;
  • aligns typical date picker with accessibility requirements;
  • uses semantic HTML structure, keyboard/navigation/focus behaviour

Current behaviour

Currently, the Profile component is not aligned with fusion DS.

Checklist

  • Commits follow our style guide
  • Related issues linked in commit messages if required
  • Screenshots are included in the PR if useful
  • All themes are supported if required
  • Unit tests added or updated if required
  • Playwright automation tests added or updated if required
  • Storybook added or updated if required
  • Translations added or updated (including creating or amending translation keys table in storybook) if required
  • Typescript d.ts file added or updated if required
  • Related docs have been updated if required

QA

  • Tested in provided StackBlitz sandbox/Storybook
  • Add new Playwright test coverage if required
  • Carbon implementation matches Design System/designs
  • UI Tests GitHub check reviewed if required

Additional context

The Typical date picker's month and year controls use native HTML <select> elements. This preserves built-in keyboard navigation, accessibility semantics, and operating-system fallback behaviour without recreating a select with JavaScript and ARIA. Carbon applies the customizable-select experience where the browser supports appearance: base-select. Other browsers display a functional native select, but its opened menu follows the browser and operating-system appearance rather than full Carbon styling.

Carbon-supported browser Picker experience
Chrome 135+ Full customizable-select styling
Edge 135+ Full customizable-select styling
Safari Native fallback; customizable select is experimental in Safari 27 beta
Firefox Native fallback; customizable select is not currently supported
docs select opened inline

@ibutakova ibutakova self-assigned this Jul 7, 2026
@ibutakova
ibutakova force-pushed the FE-7142-date-picker-accessibility branch from 2a32f23 to 71e6671 Compare July 7, 2026 08:38
@edleeks87 edleeks87 added DO NOT MERGE Work in progress This is a WIP PR so may not be ready for review labels Jul 7, 2026
@ibutakova
ibutakova force-pushed the FE-7142-date-picker-accessibility branch from 71e6671 to e4a59f5 Compare July 7, 2026 12:02
@ibutakova ibutakova changed the title Fe 7142 date picker accessibility feat(date-picker): align with fusion DS Jul 9, 2026
@ibutakova
ibutakova force-pushed the FE-7142-date-picker-accessibility branch from e629ab4 to 15cc36f Compare July 10, 2026 08:22
@ibutakova
ibutakova force-pushed the FE-7142-date-picker-accessibility branch from 15cc36f to 623c25f Compare July 10, 2026 09:14
@ibutakova
ibutakova requested a review from Copilot July 10, 2026 09:14
@ibutakova ibutakova added Pending Review Pending QA Pending UX QA and removed Work in progress This is a WIP PR so may not be ready for review DO NOT MERGE labels Jul 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown

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 updates the DateInput/DatePicker experience to align with Fusion DS designs and accessibility requirements by introducing a new “typical” implementation while retaining the existing behavior as a “legacy” variant for compatibility.

Changes:

  • Introduces a new DateInput variant API (legacy default, typical new) and extracts the legacy implementation into date-legacy.component.tsx.
  • Adds a new “typical” date picker implementation (semantic structure, focus management, month/year native <select> controls, updated keyboard behavior).
  • Updates i18n aria-labels, Storybook stories, Jest tests, Playwright CT tests, and generated skills docs to cover/describe the new variant.

Reviewed changes

Copilot reviewed 78 out of 78 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
src/style/utils/add-scrollbar-styling.ts New shared CSS helper for consistent scrollbar styling (used by typical select picker UI).
src/style/utils/add-inner-focus-styling.ts New shared CSS helper for inner focus ring styling.
src/locales/pt-pt.ts Adds new date picker aria labels; updates existing month navigation labels.
src/locales/locale.ts Extends Locale.date.ariaLabels with chooseMonth, chooseYear, closeButton.
src/locales/fr-fr.ts Adds new date picker aria labels; updates existing month navigation labels.
src/locales/fr-ca.ts Adds new date picker aria labels; updates existing month navigation labels.
src/locales/es-es.ts Adds new date picker aria labels.
src/locales/en-us.ts Adds new date picker aria labels.
src/locales/en-gb.ts Adds new date picker aria labels.
src/locales/en-ca.ts Adds new date picker aria labels.
src/locales/de-de.ts Adds new date picker aria labels; updates existing month navigation labels.
src/components/date/date.test.tsx Adjusts legacy tests to explicitly render variant="legacy"; updates ariaLabels test data.
src/components/date/date.style.ts Updates date picker width tokens to new DS sizes.
src/components/date/date.pw.tsx Adds accessibility checks for the typical picker (including range-mode fixture scenario).
src/components/date/date.component.tsx Refactors DateInput into a variant switch delegating to legacy vs typical implementations.
src/components/date/date-typical.stories.tsx Adds Storybook stories and documentation for the typical variant (incl. browser compatibility notes).
src/components/date/date-legacy.stories.tsx Reorganizes legacy stories under Date Input/Legacy and pins variant="legacy".
src/components/date/date-legacy.mdx Updates docs to point at the legacy story file and minor formatting cleanups.
src/components/date/date-legacy.component.tsx New extracted legacy implementation (previous date.component.tsx logic).
src/components/date/date-legacy-test.stories.tsx Updates legacy test stories to pin variant="legacy" and reorganizes story path.
src/components/date/date-legacy-interaction.stories.tsx Updates legacy interaction stories to pin variant="legacy" and reorganizes story path.
src/components/date/components.test-pw.tsx Adds a typical DateInput test fixture and ensures legacy fixtures explicitly set variant.
src/components/date/internal/utils.test.ts Minor test param rename cleanup.
src/components/date/internal/date-picker/date-picker.test.tsx Updates test locale objects to include new aria label keys.
src/components/date/internal/date-picker/date-picker.component.tsx Minor typing + floating-ui middleware changes; wraps eslint disables for tab guard.
src/components/date/internal/next/index.ts Adds __next__ exports for typical DateInput and types.
src/components/date/internal/next/date-typical.test.tsx Adds Jest coverage for typical focus/navigation/semantics and interactions.
src/components/date/internal/next/date-typical.component.tsx New typical DateInput implementation (semantic layout + picker integration).
src/components/date/internal/next/date-typical-test.stories.tsx Adds a typical test story entry for tooling/tests.
src/components/date/internal/next/date-typical-interaction.stories.tsx Adds an interaction story for typical variant.
src/components/date/internal/next/internal/utils.ts New shared utilities for typical date parsing/formatting/event creation.
src/components/date/internal/next/internal/utils.test.ts Unit tests for the new typical utilities.
src/components/date/internal/next/internal/subtle-select/use-customizable-select-markup.ts Hook inserting customizable-select markup for supported browsers (React 18 limitation workaround).
src/components/date/internal/next/internal/subtle-select/subtle-select.test.tsx Unit tests for the new subtle select component.
src/components/date/internal/next/internal/subtle-select/subtle-select.style.ts Styling for native/customizable select picker, including picker pseudo-element styling.
src/components/date/internal/next/internal/subtle-select/subtle-select.config.ts Size config tokens for subtle select.
src/components/date/internal/next/internal/subtle-select/subtle-select.component.tsx New subtle select component used for month/year controls.
src/components/date/internal/next/internal/subtle-select/index.ts Barrel export for subtle select.
src/components/date/internal/next/internal/hooks/useDatePickerMonthYearSelection.ts Month/year selection logic + min/max clamping and year range generation.
src/components/date/internal/next/internal/hooks/useDatePickerMonthSync.ts Keeps focused month in sync with selection/open state.
src/components/date/internal/next/internal/hooks/useDatePickerLocale.ts Typical picker weekday localization helpers.
src/components/date/internal/next/internal/hooks/useDatePickerKeyboardNavigation.ts Implements picker focus trap + keyboard navigation.
src/components/date/internal/next/internal/hooks/useDatePickerInFlatTable.ts Coordinates with FlatTable to avoid interaction conflicts while picker is open.
src/components/date/internal/next/internal/hooks/useDatePickerFocus.ts Initial focus behavior when opening picker.
src/components/date/internal/next/internal/hooks/useDatePickerAccessibility.ts Wires grid labelling to month/year controls.
src/components/date/internal/next/internal/hooks/useDateInputPickerInteractions.ts Typical DateInput open/close and event orchestration.
src/components/date/internal/next/internal/hooks/useDateInputAccessibility.ts Typical DateInput IDs/aria-describedby/validation wiring.
src/components/date/internal/next/internal/date-picker/index.ts Barrel export for typical picker.
src/components/date/internal/next/internal/date-picker/date-picker.utils.ts Shared date picker utility functions (bounds parsing/clamping).
src/components/date/internal/next/internal/date-picker/date-picker.utils.test.ts Unit tests for typical date picker utilities.
src/components/date/internal/next/internal/date-picker/date-picker.types.ts Types for typical date picker component/props.
src/components/date/internal/next/internal/date-picker/date-picker.style.ts Typical date picker styling (Fusion DS-aligned).
src/components/date/internal/next/internal/date-picker/date-picker.component.tsx Typical popover date picker implementation using floating-ui + Popover.
src/components/date/internal/next/internal/date-input-field/date-input-validation.component.tsx Typical inline validation rendering for DateInput.
src/components/date/internal/next/internal/date-input-field/date-input-field.style.ts Typical DateInput field layout/styling (label + input + trigger).
src/components/date/internal/next/internal/date-input-field/date-input-field.config.ts Typical DateInput sizing config tokens.
src/components/date/internal/next/internal/date-input-field/date-input-field.component.tsx Typical DateInput field composition using internal Input.
src/components/date/internal/next/internal/date-input-field/date-input-field-label.style.ts Typical label/hint styling for DateInput.
src/components/date/internal/next/internal/date-input-field/date-input-field-label.component.tsx Typical label/hint component for DateInput.
src/components/date/internal/next/internal/date-input-field/date-input-calendar-trigger.component.tsx Typical calendar trigger button + ARIA wiring.
src/components/date/internal/next/internal/calendar/calendar.component.tsx Typical calendar wrapper around react-day-picker with custom components.
src/components/date/internal/next/internal/calendar/calendar-weekday.style.ts Typical weekday header cell styling.
src/components/date/internal/next/internal/calendar/calendar-weekday.component.tsx Typical weekday header rendering (SR-only full names).
src/components/date/internal/next/internal/calendar/calendar-header.style.ts Header layout styling for month/year selectors.
src/components/date/internal/next/internal/calendar/calendar-header.component.tsx Typical month/year selector header implementation.
src/components/date/internal/next/internal/calendar/calendar-footer.style.ts Typical footer styling for Close action.
src/components/date/internal/next/internal/calendar/calendar-day-button.component.tsx Typical day button markup (SR text + today indicator).
src/components/date-range/date-range.test.tsx Updates locale override test data to include new aria label keys.
src/components/date-range/date-range.stories.tsx Updates locale override stories to include new aria label keys.
src/components/date-range/date-range-interaction.stories.tsx Updates interaction stories to include new aria label keys.
src/internal/input/input-style-overrides.style.ts Splits legacy vs typical date input styling overrides.
skills/carbon-react/index.md Adds new “next” docs entries for typical date components.
skills/carbon-react/components/date-picker-weekday-next.md New generated docs for next weekday component export.
skills/carbon-react/components/date-picker-typical-next.md New generated docs for next typical date picker export.
skills/carbon-react/components/date-labelset-next.md New generated docs for next date labelset export.
skills/carbon-react/components/date-input.md Updates generated DateInput docs (props list changes + examples removed).
skills/carbon-react/components/date-input-typical-component-next.md New generated docs for next typical date input component export.

Comment thread src/locales/pt-pt.ts Outdated
Comment thread src/locales/fr-fr.ts Outdated
Comment thread src/locales/fr-ca.ts Outdated
Comment thread src/locales/de-de.ts Outdated
Comment thread src/components/date/__internal__/__next__/date-typical.test.tsx
Comment thread src/components/date/__internal__/__next__/date-typical.test.tsx
Comment on lines +33 to +38
const canvas = within(canvasElement);
const calendarIcon = canvas.getByTestId("icon");
await userEvent.click(calendarIcon);
const navigationIcon = canvas.getByRole("button", { name: "Next month" });
await userEvent.click(navigationIcon);
},
Comment on lines +33 to +37
const dateInoutTypicalMinWidth = {
small: "128px",
medium: "144px",
large: "176px",
} as const;
Comment thread src/components/date/date.component.tsx Outdated
Comment on lines +11 to +13
type DateInputPickerProps = NonNullable<DateInputLegacyProps["pickerProps"]> & {
mode?: DayPickerProps["mode"];
};
Comment thread skills/carbon-react/components/date-input.md Outdated

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.

comment: we don't need this component, you should get all this for free by using the textbox/__internal__/__next__/text-input component

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Full text-input reuse is not drop-in. it requires date-specific overrides for several layout rules, interactive calendar button and focus-model difference is also present. I can reuse Hint, ValidationMessage as input primitives, but I think date-specific field wrapper should be present for typical. Let it own split control focus, button semantic, dimensions

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.

We need to reuse the TextInput as any updates to it going forward will need to be reflected in all the other text based inputs. You should be able to pass the button via the inputIcon prop to pass a node

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok, let me try

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.

comment: we don't need this component, you should get all this for free by using the textbox/internal/next/text-input component

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.

comment: As far as I was aware the only difference between the legacy and typical variants was how keyboard navigation works. If that's the case a whole component seem excessive as there's likely a lot of code that's duplicated. I think the ticket is poorly worded and we can just add a variant and guard the specific differences etc

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.

comment: I believe the intention was to use the native selects here not build another custom one

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You mean the earlier decision was to accept native select presentation until styling the list is supported across browsers? This is not another custom select, it is enhanced native customizable select where supported

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.

Yes the original decision was to not add any custom styling as we didn't want to rely on styling that might not gain full cross-browser support. As it's a progressive enhancement I'm happy to defer to other reviewers

}: DateInputTypicalProps,
ref,
) => {
const wrapperRef = useRef<HTMLDivElement>(null);

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.

comment: as mentioned above there's a lot of duplication between this and legacy, I think the only difference between the two is whether you can open it via keyboard so I dont' think it all needs to be separate components (don't mind if they are as long as they're DRY etc)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks. I agree, there is duplication. but sharing logic would require refactoring the existing legacy implementation rather than simply reusing.
One strong difference is the required dom composition. Legacy navigation is supplied through rdp and rendered via .rdp-months, but Typical treats year/month controls outside rdp tree, where month/year selection, calendar and close button are separate sections. So, my preference was to share that controller logic while retaining separate navigation rather than adding variant conditions throughout the markup, accessibility logic, focus handling, styles, etc.
I think I can reuse duplicated 1) utils (date parsing and values) - the ones I already copied and extracted to typical utils - as no rendering involved, no variant prop treatment. 2) date picker locale can be shared. 3) probably month synchronization (let me re-check). If both variants are expected to be maintained long-term< I can follow up extracting pure utils to be sharable

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.

The legacy part is how the keyboard navigation works for the component (it can't be opened via keyboard etc) the rest of it should be the same as far as I'm aware. The legacy version still needs the new dropdowns and calendar/picker layout and styling.

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.

comment: We should really only have one skill file for the a Date component, a lot of these (typical-component, labelset-next, date-pickerptypical, date-picker-weekday) don't have any real useful skill information

Comment thread src/locales/fr-fr.ts Outdated
dateFnsLocale: () => frFRDateLocale,
ariaLabels: {
previousMonthButton: () => "Mois précédent",
previousMonthButton: () => "Mois prcdent",

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.

comment: this is incorrect

Comment thread src/locales/fr-ca.ts Outdated
dateFnsLocale: () => frCADateLocale,
ariaLabels: {
previousMonthButton: () => "Mois précédent",
previousMonthButton: () => "Mois prcdent",

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.

comment: this is incorrect

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I messed up with accent marks. fixed

Comment thread src/locales/fr-fr.ts
previousMonthButton: () => "Mois précédent",
previousMonthButton: () => "Mois prcdent",
nextMonthButton: () => "Mois suivant",
chooseMonth: () => "Choisir le mois",

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.

question: have these additional locale values come from the translation team?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I messed up with accent marks and rolled back these changes. Translation team is a total mystery for me) I'll find out

and operating-system fallback behaviour without recreating a select with
JavaScript and ARIA.

Carbon applies the customizable-select experience where the browser supports

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.

comment: I think the decision was that we were okay with using native select until support for styling the list is introduced across browser

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's just a comment about what developer can and what can not customize. Let me know if I should remove it

@tomdavies73 tomdavies73 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.

I've had a look over this @ibutakova, I think we may have to pivot the approach here to be a lot simpler with the use of a native <select> doing most of the heavy lifting with styling only being applied to the closed input.

The dropdown can remain unstyled and be handled by the respective OS. We may be able to remove a lot of the additional internal components/hooks added here and revert to the original component. With some small enhancement and adjustments made, to achieve the design or close to the design without a large overhaul.

We need to try and use already available internal componentry where possible here, some of the stuff added does already exist in Carbon somewhere.

On the locales, we typically only add en-gb locales as default if you do need to add any locales. We can then help you request additional translations from the translations team who will send these over to you when they're ready.

Happy to have a chat with you on this if needed to explore your options. Also agree with all of @edleeks87's comments, I just thought I'd leave a larger more general comment here instead 👍

@ibutakova ibutakova closed this Jul 21, 2026
@ibutakova

Copy link
Copy Markdown
Contributor Author

Closed in favor of #8085

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

Development

Successfully merging this pull request may close these issues.

4 participants