Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fields] Enable the new field DOM structure by default #14651

Merged

Conversation

flaviendelangle
Copy link
Member

@flaviendelangle flaviendelangle commented Sep 17, 2024

Closes #14477

If possible, this PR should be merged as soon as the next branch is prepared so that I can open the PR to #14796 which also impacts most of the interfaces in the package.

Work

  • Enable enableAccessibleFieldDOMStructure when the prop is not provided and render the right text field
  • Change the default value of the TEnableAccessibleFieldDOMStructure generic in every component and interface using it
  • Stop usign enableAccessibleFieldDOMStructure={true} in doc and tests
  • Create the migration guide for v8 and move the guide to migrate to the new DOM structure there
  • Update the "Custom field" page to use the new DOM structure by default an only advertise the legacy one for Joy UI
  • Use the terminology "Accessible DOM structure" / "Non-accessible DOM structure" everywhere instead of "v6" / "v7" or "legacy"

Changelog

Pickers

  • The default DOM structure of the field has changed.
    Before version v8.x, the fields' DOM structure consisted of an <input />, which held the whole value for the component, but unfortunately presents a few limitations in terms of accessibility when managing multiple section values.

    Starting with version v8.x, all the field and picker components come with a new DOM structure that allows the field component to set aria attributes on individual sections, providing a far better experience with screen readers.

    Fallback to the non-accessible DOM structure:

    <DateField enableAccessibleFieldDOMStructure={false} />
    <DatePicker enableAccessibleFieldDOMStructure={false} />
    <DateRangePicker enableAccessibleFieldDOMStructure={false} />

    Migrate slotProps.field:

    When using slotProps.field to pass props to your field component,
    the field consumes some props (e.g: shouldRespectLeadingZeros) and forwards the rest to the TextField.

    • For the props consumed by the field, the behavior should remain exactly the same with both DOM structures.

      Both components below will respect the leading zeroes on digit sections:

      <DatePicker
        slotProps={{ field: { shouldRespectLeadingZeros: true } }}
        enableAccessibleFieldDOMStructure={false}
       />
      <DatePicker
        slotProps={{ field: { shouldRespectLeadingZeros: true } }}
      />
    • For the props forwarded to the TextField,
      you can have a look at the next section to see how the migration impact them.

      Both components below will render a small size UI:

      <DatePicker
        slotProps={{ field: { size: 'small' } }}
        enableAccessibleFieldDOMStructure={false}
       />
      <DatePicker
        slotProps={{ field: { size: 'small' } }}
      />

    Migrate slotProps.textField:

    If you are passing props to slotProps.textField,
    these props will now be received by PickersTextField and should keep working the same way as before.

    Both components below will render a small size UI:

    <DatePicker
      slotProps={{ textField: { size: 'small' } }}
      enableAccessibleFieldDOMStructure={false}
    />
    <DatePicker
      slotProps={{ textField: { size: 'small' } }}
    />

    Side note: If you are passing inputProps to slotProps.textField, these props will now be passed to the hidden <input /> element.

    Migrate slots.field:

    If you are passing a custom field component to your pickers, you need to create a new one that is using the accessible DOM structure.
    This new component will need to use the PickersSectionList component instead of an <input /> HTML element.

    You can have a look at the Using a custom input to have a concrete example.

    Migrate slots.textField:

    If you are passing a custom TextField component to your fields and pickers,
    you need to create a new one that is using the accessible DOM structure.

    You can have a look at the Wrapping PickersTextField section to have a concrete example.

    Side note: If your custom TextField was used to apply a totally different input that did not use @mui/material/TextField,
    please consider having a look at the Using a custom input section which uses slots.field.
    This approach can be more appropriate for deeper changes.

    Migrate the theme:

    If you are using the theme to customize MuiTextField,
    you need to pass the same config to MuiPickersTextField:

    const theme = createTheme({
      components: {
        MuiTextField: {
          defaultProps: {
            variant: 'outlined',
          },
          styleOverrides: {
            root: {
              '& .MuiInputLabel-outlined.Mui-focused': {
                color: 'red',
              },
            },
          },
        },
        MuiPickersTextField: {
          defaultProps: {
            variant: 'outlined',
          },
          styleOverrides: {
            root: {
              '& .MuiInputLabel-outlined.Mui-focused': {
                color: 'red',
              },
            },
          },
        },
      },
    });

    If you are using the theme to customize MuiInput, MuiOutlinedInput or MuiFilledInput,
    you need to pass the same config to MuiPickersInput, MuiPickersOutlinedInput or MuiPickersFilledInput:

    const theme = createTheme({
      components: {
        // Replace with `MuiOutlinedInput` or `MuiFilledInput` if needed
        MuiInput: {
          defaultProps: {
            margin: 'dense',
          },
          styleOverrides: {
            root: {
              color: 'red',
            },
          },
        },
        // Replace with `MuiPickersOutlinedInput` or `MuiPickersFilledInput` if needed
        MuiPickersInput: {
          defaultProps: {
            margin: 'dense',
          },
          styleOverrides: {
            root: {
              color: 'red',
            },
          },
        },
      },
    });

    If you are using the theme to customize MuiInputBase,
    you need to pass the same config to MuiPickersInputBase:

    const theme = createTheme({
      components: {
        MuiInputBase: {
          defaultProps: {
            margin: 'dense',
          },
          styleOverrides: {
            root: {
              color: 'red',
            },
          },
        },
        MuiPickersInputBase: {
          defaultProps: {
            margin: 'dense',
          },
          styleOverrides: {
            root: {
              color: 'red',
            },
          },
        },
      },
    });

@flaviendelangle flaviendelangle self-assigned this Sep 17, 2024
@flaviendelangle flaviendelangle added breaking change component: pickers This is the name of the generic UI component, not the React module! v8.x labels Sep 17, 2024
Copy link
Member

@arthurbalduini arthurbalduini left a comment

@arthurbalduini
Copy link
Member

Maybe we already want to remove the "v6" x "v7" terminology for good ?

Although I think it can make sense, I also see it as questionable since adding new suffixes could make it more verbose and hardly to read, plus we are already used to the v6 x v7 nomenclature. I wouldn't mind leaving the renaming for v9 once we remove the non-accessible-v6 input

Copy link
Member

@arthurbalduini arthurbalduini left a comment

Choose a reason for hiding this comment

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

LGTM 👏
Nice to see so many removed lines, specially in our tests ! 🎉

I'm leaving the approve, I believe the v7xv6 nomenclature doesn't block this PR 🙂

@flaviendelangle
Copy link
Member Author

flaviendelangle commented Oct 16, 2024

Thanks for the deep dive on the v6/v7 nomenclature.

Although I think it can make sense, I also see it as questionable since adding new suffixes could make it more verbose and hardly to read, plus we are already used to the v6 x v7 nomenclature. I wouldn't mind leaving the renaming for v9 once we remove the non-accessible-v6 input

I would differenciate public usage of the nomenclature and internal one.
The public usage is "accessible DOM structure", not "v7 DOM structure", so I think any public usage should still follow this nomenclature as muche as possible.
From what I can see, the only public interfaces remaining with v6/v7 is BaseForwardedV6SingleInputFieldProps/BaseForwardedV7SingleInputFieldProps which I can rename but is very rarely used (and is even less useful with the multi input field going away).

All the rest is purely internal, I can rename it for consistency, but as you said everything will go away in v9 so it may not be worth the effort.

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 17, 2024
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Oct 18, 2024
@flaviendelangle flaviendelangle merged commit 509b12d into mui:master Oct 22, 2024
16 checks passed
@flaviendelangle flaviendelangle deleted the enabledAccessibleFieldDOMStructure branch October 22, 2024 15:56
## New DOM structure for the field

Before version `v8.x`, the fields' DOM structure consisted of an `<input />`, which held the whole value for the component,
but unfortunately presents a few limitations in terms of accessibility when managing multiple section values.
Copy link
Member

Choose a reason for hiding this comment

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

How about we document those limitations? Helping people decide if they want to care about it or stick to the previous approach.

By the way, it's possible to inspect native inputs:

SCR-20241123-phnw
SCR-20241123-phlt

Copy link
Member

Choose a reason for hiding this comment

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

Raised #15596 😉

By the way, it's possible to inspect native inputs:

Yes, thank you for bringing this up. 👍
It's always nice to have a reference to check how others are doing similar things. 👌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change component: pickers This is the name of the generic UI component, not the React module! v8.x
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[pickers] Make the <input /> version of the fields opt-in
5 participants