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

[Joy] Add Autocomplete component #34315

Merged
merged 211 commits into from Nov 8, 2022
Merged

Conversation

siriwatknp
Copy link
Member

@siriwatknp siriwatknp commented Sep 15, 2022

Preview

🖥 https://deploy-preview-34315--material-ui.netlify.app/joy-ui/react-autocomplete/

Internal changes

There are some logics in useAutocomplete that tie to Material UI autocomplete structure, so I added internal options for using with Joy UI.

Some CSS variables in Joy UI components, e.g. Input, Chip, are updated to work seamlessly with the Autocomplete when size prop changes.

Components

  • Autocomplete: uses useAutocomplete from MUI Base
  • AutocompleteListbox: reuses the same styles as List which lets developers build a custom list box if needed.
  • AutocompleteOption: reuses the same styles as ListItemButton which lets developers build a custom option if needed.

Differences compared to Material UI

1. Autocomplete does not expose renderInput. It is an input in itself which lets developers control the global variants, colors, and sizes as if they are using the Input component.

Joy UI:

<Autocomplete options={[...]} /> // the UI is similar to <Input />
<FormControl>
  <FormLabel>Label</FormLabel>
  <Autocomplete options={[...]} />
</FormControl>

Material UI:

<Autocomplete
  renderInput={params => <TextField {...params} />}
/>

2. Tag composition

Joy UI Chip does not support onDelete so developers have to compose by themselves:

Joy UI:

<Autocomplete
   renderTags={(value, getTagProps) =>
      value
        .filter((x, index) => index === 1)
        .map((option, index) => (
          <Chip key={index} endDecorator={<ChipDelete {...getTagProps({ index })} />}>
            {option.title}
          </Chip>
        ))
    }
/>

Material UI:

<Autocomplete
  renderTags={(value, getTagProps) =>
    value
      .filter((x, index) => index === 1)
      .map((option, index) => <Chip label={option.title} {...getTagProps({ index })} />)
  }
/>

This approach is easier to customize if developers don't want to show the delete button.

3. AutocompleteListbox

A new component used by default in Autocomplete and can be used for complex customization. Material UI uses plain ul + styled-component for customization.

Joy UI:

function Listbox(props) {
  return (
    <AutocompleteListbox {...props} />
  )
}
<Autocomplete
  components={{ listbox: Listbox }}
/>

Material UI:

const PopperComponent = styled(Popper)({
  ...custom styles
})
<Autocomplete
  PopperComponent={PopperComponent}
/>

4. AutocompleteOption

Similar to the list box customization, it is used by default in Autocomplete component. Developers can use it to customize the option appearance.

Joy UI:

<Autocomplete
  renderOption={(props, option) => (
    <AutocompleteOption {...props}>
      ...
    </AutocompleteOption>
  )}
/>

Material UI:

<Autocomplete
  renderOption={(props, option) => (
    <Box component="li" sx={{ '& > img': { mr: 2, flexShrink: 0 } }} {...props}>
      <img {...} />
      {option.label} ({option.code}) +{option.phone}
    </Box>
  )}
/>

Test

👍 The test suite is the same as Material UI Autocomplete tests.

Comparison

Lines of code: This can be comparable because both Material UI and Joy UI are using the same useAutocomplete from MUI Base.

Material Joy % change
Autocomplete 1085 1070 -1.38
total 1085 1070 -1.38

Joy UI reduces styles by ~50% compared to Material UI which still produces a similar appearance.


@siriwatknp
Copy link
Member Author

@michaldudak I did what you suggested about the input slot and the result is amazing. Even though it is a bit more code to add but the abstraction is a lot better. Now the customization experience is similar to the Input component! I like it a lot.

We can completely think of autocomplete as an enhanced version of the Input 💖. All the tests remain the same, just without the renderInput.

@siriwatknp
Copy link
Member Author

Don't have anything to add in regards to the component. One important thing tough related to the docs, we should add TypeScript demos to all Joy UI components. Not adding them leaves us one step behind. This is really important in my opinion. I remember @michaldudak mentioned this once too.

Added TypeScript demos.

@siriwatknp
Copy link
Member Author

By getting rid of renderInput prop, we won't encounter this kind of issue in Joy UI.

@siriwatknp siriwatknp merged commit 00a0d58 into mui:master Nov 8, 2022
@oliviertassinari oliviertassinari added the component: autocomplete This is the name of the generic UI component, not the React module! label Nov 13, 2022
@oliviertassinari
Copy link
Member

oliviertassinari commented Nov 13, 2022

By getting rid of renderInput prop

@flaviendelangle took the same direction in mui/mui-x#5504 by not exposing the TextField as a React.createElement. For the history of the date picker, v3 didn't have renderInput https://material-ui-pickers.dev/demo/datepicker, v4 introduced renderInput in mui/material-ui-pickers#1671. The PR's description gives a bit of context:

Our new API to render the text field, that solves a lot of problems! Like spreading props down to text field, override them, override classes for the picker – and saves a lot of bundlesize.

@dmtrKovalenko do you remember was were the main struggles of the date picker in v3 without renderInput that this API was trying to solve?


It will be interesting to see the new class of issues that developers raise without renderInput on Joy UI. Given more time to get community feedback, we should then be able to have clarity on the direction to pick to generalize the pattern 😁.

@dmtrKovalenko
Copy link
Member

Yes I think I remember that was about reducing amount of spreaded props.

So for customising input we don't need to pass 17 props to the root component and make root components props to be spread into the modal

the-mgi pushed a commit to the-mgi/material-ui that referenced this pull request Nov 17, 2022
daniel-rabe pushed a commit to daniel-rabe/material-ui that referenced this pull request Nov 29, 2022
feliperli pushed a commit to jesrodri/material-ui that referenced this pull request Dec 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: autocomplete This is the name of the generic UI component, not the React module! package: joy-ui Specific to @mui/joy
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants