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

[Autocomplete] 'renderTags' ignored when 'multiple' is false #26440

Open
2 tasks done
Idonoghue opened this issue May 24, 2021 · 22 comments · May be fixed by #45387
Open
2 tasks done

[Autocomplete] 'renderTags' ignored when 'multiple' is false #26440

Idonoghue opened this issue May 24, 2021 · 22 comments · May be fixed by #45387
Assignees
Labels
component: autocomplete This is the name of the generic UI component, not the React module! discussion docs Improvements or additions to the documentation

Comments

@Idonoghue
Copy link

Idonoghue commented May 24, 2021

  • The issue is present in the latest release.
  • I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 😯

On v5 alpha, when passing renderTags to Autocomplete when multiple is false the renderTags prop will be ignored.

Expected Behavior 🤔

renderTags should be used to render the selected item(s) in the Input no matter what multiple is set to.

Steps to Reproduce 🕹

Comment line 11 of this code sandbox

Context 🔦

We have a single select Autocomplete where we set the renderOption prop to render a custom element that includes a small profile pic. However once one option is selected there is currently no way to render this custom element in the Input of the Autocomplete

Your Environment 🌎

`npx @material-ui/envinfo`
  System:
    OS: Linux 5.8 Pop!_OS 20.04 LTS
  Binaries:
    Node: 14.15.1 - ~/.nvm/versions/node/v14.15.1/bin/node
    Yarn: 1.22.5 - /usr/bin/yarn
    npm: 6.14.10 - ~/Projects/clinical-dashboard-v2/node_modules/.bin/npm
  Browsers:
    Chrome: 89.0.4389.82 <--- using this one
    Firefox: 86.0
  npmPackages:
    @emotion/react: ^11.0.0 => 11.1.4 
    @emotion/styled: ^11.0.0 => 11.0.0 
    @material-ui/core: 5.0.0-alpha.34 => 5.0.0-alpha.34 
    @material-ui/lab: 5.0.0-alpha.34 => 5.0.0-alpha.34 
    @material-ui/private-theming:  5.0.0-alpha.33 
    @material-ui/styled-engine:  5.0.0-alpha.34 
    @material-ui/styles:  5.0.0-alpha.33 
    @material-ui/system:  5.0.0-alpha.34 
    @material-ui/types:  6.0.0 
    @material-ui/unstyled:  5.0.0-alpha.34 
    @material-ui/utils:  5.0.0-alpha.33 
    @types/react: ^17.0.3 => 17.0.3 
    react: ^17.0.1 => 17.0.1 
    react-dom: ^17.0.1 => 17.0.1 
    styled-components: ^5.2.1 => 5.2.1 
    typescript: ^4.2.0 => 4.2.4 
@Idonoghue Idonoghue added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label May 24, 2021
@Idonoghue
Copy link
Author

I also wonder if this was perhaps intentional. Regardless, I believe there is enough of a use case to either allow renderTags to work with multiple={false} or add some other prop to override the display of a single selected option.

I'm curious what your workaround was @degzhaus. Were you able to do it somehow inside the renderInput prop?

@eps1lon
Copy link
Member

eps1lon commented Jul 13, 2021

Thanks for the feedback.

What we consider a "tag" is a combination of a value and an affordance to de-select that value. There's no need to de-select a single value in a single-select Autocomplete so we don't even attempt to "render tags".

The purpose of renderTags is not really to display a different label. That's what getOptionLabel is for.

So we definitely do lack some clearer documentation for the Autocomplete.

As to your specific issue: Could you explain a bit more what UI you're trying to build? Then we can discuss what kind of API could solve this problem.

@eps1lon eps1lon added component: autocomplete This is the name of the generic UI component, not the React module! discussion docs Improvements or additions to the documentation and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jul 13, 2021
@Idonoghue
Copy link
Author

Thanks for the response @eps1lon . That makes a lot of sense. Looking at it now everything inside the getTagProps passed to the renderTags function wouldn't apply to a single select.

To describe a bit further our use case, we have a custom component, <EntityLabel/> that renders formatted text with a profile pic. It is trivially easy to render these components as the list of options for the Autocomplete using renderOption. However once one is selected and displayed in the input, there is no render- prop in the Autocomplete API for a custom component like there is for multiple selected values.

@kgrhartlage
Copy link

kgrhartlage commented Aug 9, 2021

This would be an incredibly helpful change for us also. We need to show a device status icon - and ideally also a device class icon - not only on the options, but also for the selected value. We use this type of device select for both single and multiselection. IIUC one can only render a string unless multiselection is enabled, which results in an inconsistent UI in our case. And since we cannot omit the status icon, we currently add it to the textfield label, which is of course very undesirable.

screenshots

CleanShot 2021-08-09 at 16 08 26

CleanShot 2021-08-09 at 16 24 53

@Harsha99unifo
Copy link

I am using Autocomplete to display the selected popup as chip and typed text as normal text

@G1itcher
Copy link

This is something that would be very helpful for us also

@ZeeshanTamboli
Copy link
Member

I can think of the following approaches:

  1. We could have a renderTag or renderSingleValue API prop for this.
  2. We can have a components prop with SingleValue slot like what react-select does in https://codesandbox.io/s/s0yc5?module=/example.tsx&file=/example.tsx.

We should also update the API docs for renderTags that it works only when multiple is true.

@oliviertassinari @michaldudak What do you guys think?

@yurivasconcelos

This comment was marked as spam.

@michaldudak
Copy link
Member

I see how this may be useful.

A thing to note, though, is that rendering anything else than a default string will break the current autocompletion logic.

Let's say we have a list of colors and when selected, we display a swatch before the color name in the textbox:

🟥 red
--------
red
green
blue

When we now focus the textbox and press Backspace, we are left with 🟥 re, which does not match any of the options.

We could overcome this by disallowing to edit the selected value and clearing the input completely when Backspace, Delete, or any character key is pressed, similar to how react-select does it. This logic would kick in only if we override what is displayed in the textbox.
Alternatively, we could display the custom value only if the textbox is not focused. Doing so would let us leave the current autocompletion logic.

Do you have any preferences in this matter?

cc @mnajdova

@ggmartins091
Copy link

ggmartins091 commented May 4, 2022

+1 for this! We would also be helped a lot if this was a feature.

Edit: found out our team is actually using this approach: https://codesandbox.io/s/material-demo-forked-ijzbt?file=/demo.js

degzhaus' suggestion didn't work but the one used on this csb did. Basically adding ...params.InputProps to the TextField.

@humarkx

This comment was marked as spam.

@ggmartins091
Copy link

ggmartins091 commented Jul 20, 2022

@michaldudak

Aren't we be able to keep the actual value somewhere else and have the rendered component not interfere with our autocompletion?

Based on your suggestion and example, when deleting the character "d", could we make it so that the swatch goes away?

Idk if I'm going to far here, but basically having a way to map a value to its renderTag, so "red" maps to "🟥 red", as soon as we deleted a single character from the input, there won't be any value that maps to that, so we go back to normal rendering the text typed.

So instead of this

🟥 re
--------
red
green
blue

We would get this:
since that the tag "🟥 re" doesn't have any value mapped to it, (not a valid option)

re
--------
red
green
blue

-edit
ps. I dont know the inner workings of the AutoComplete component, so maybe I'm just talking non sense here, also maybe this approach is too expensive.

@Idonoghue
Copy link
Author

From a UI POV I personally prefer the latter solution where backspace removes the selected value and completely clears the input. This aligns with Autocomplete behavior when multiple={true}. Once an item has been selected a single backspace to remove selected item feels intuitive and desired.

The case where users instead want to view similar items to the one they just removed (search results for 're') seems less likely. One caveat to that may be if freeSolo={true}? I struggle to think of a real world use case where renderTags and freeSolo are used together.

@yuklai
Copy link

yuklai commented Aug 10, 2022

The gmail to field would be something that supports renderTags and freeSolo={true}?

@michaldudak
Copy link
Member

Aren't we be able to keep the actual value somewhere else and have the rendered component not interfere with our autocompletion?

Based on your suggestion and example, when deleting the character "d", could we make it so that the swatch goes away?

Idk if I'm going to far here, but basically having a way to map a value to its renderTag, so "red" maps to "🟥 red", as soon as we deleted a single character from the input, there won't be any value that maps to that, so we go back to normal rendering the text typed.

I think it could be confusing if the rendered value changed during editing.

I'm leaning towards a solution similar to how the Autocomplete works in multiple mode, but as @Idonoghue noted, there are rough edges here as well.

If someone is willing to prototype a solution, I'll be happy to review it and discuss the solutions for problems that arise.

@prajeeshbs
Copy link

Is there any solution for this?
The workaround that i am doing now is to add a startAdornment in the textfield and display whatever is needed. Then i hide the label of the autocomplete component using getOptionLabel: () => "",

@emil-datcu
Copy link

Yo :)

I would need this 'feature' as well... I just want to be able to style the displayed option like I'm able to style it for the multiple=true.
My example 'need' would look like this:
image

If this would cause too much of an overhead for the autocomplete component, does anyone has any other workaround that could be used to achieve something like this or it's just impossible for the single autocomplete to have the displayed value styled any other way?

Thanks 🤙

@clxy
Copy link

clxy commented Mar 19, 2024

My workaround/idea is

  1. Keep the origin value of multiple, and set it to true anyway.
  2. And change the new value to the last element of selected values in onChange when origin multiple is false.
... 
const { multiple, ...props } = p
...
<MuiAutocomplete
      multiple={true}
      onChange={(e, d) => {
        const newValue = multiple ? d : Array.from(d).slice(-1)
        props.onChange?.call(null, e, newValue)
      }}
     ...
     {... props}

Still, I’m waiting for the official solution as well.

@Liam26
Copy link

Liam26 commented Jun 11, 2024

Any news on an official solution for this? Would be extremely helpful and it's been 3 years 🙏

@Liam26
Copy link

Liam26 commented Jun 11, 2024

Yo :)

I would need this 'feature' as well... I just want to be able to style the displayed option like I'm able to style it for the multiple=true. My example 'need' would look like this: image

If this would cause too much of an overhead for the autocomplete component, does anyone has any other workaround that could be used to achieve something like this or it's just impossible for the single autocomplete to have the displayed value styled any other way?

Thanks 🤙

Did you ever find a workaround for this?, your exact case is what i'm trying to do I want to have an autocomplete field that is a single select rather than allowing multiple but I want to style it to match my multiple selects by having the single selected option look like a chip as well.

@ZadynB
Copy link

ZadynB commented Nov 26, 2024

+1 for this! We would also be helped a lot if this was a feature.

Edit: found out our team is actually using this approach: https://codesandbox.io/s/material-demo-forked-ijzbt?file=/demo.js

degzhaus' suggestion didn't work but the one used on this csb did. Basically adding ...params.InputProps to the TextField.

A workaround I came up with entailed using a state and the adornment used in the comment above.

So, for example, my autocomplete is one for picking colours. You can display the colour and text just fine with renderOption. But when the value is selected, I call the setColour action to set the colour state. Then in the adornment I have a div that's a box with the background set as the state value (colour hex code).

@ZeeshanTamboli
Copy link
Member

I created a PR to add this feature request: #45387

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! discussion docs Improvements or additions to the documentation
Projects
None yet
Development

Successfully merging a pull request may close this issue.