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] Multiple with many options take too much space #19137

Closed
1 task done
mzbyszynski opened this issue Jan 8, 2020 · 18 comments · Fixed by #20209
Closed
1 task done

[Autocomplete] Multiple with many options take too much space #19137

mzbyszynski opened this issue Jan 8, 2020 · 18 comments · Fixed by #20209
Labels
component: autocomplete This is the name of the generic UI component, not the React module! new feature New feature or request waiting for 👍 Waiting for upvotes

Comments

@mzbyszynski
Copy link

  • I have searched the issues of this repository and believe that this is not a duplicate.

Summary 💡

Currently for an Autocomplete with the multiple option, the height of the autocomplete will grow as more items are selected and more chips are displayed. It would be useful to have an option to limit the number of rows of chips that can be displayed, so that a vertically growing list of chips will not disrupt the layout of the rest of the page.

Examples 🌈

Here is the current behavior from material-ui component demo:
Screen Shot 2020-01-08 at 6 09 34 PM

Here is a design spec for multi-line that has vertical scrolling rather than horizontal (this is actually what we were asked to implement)
Screen Shot 2020-01-08 at 6 17 34 PM

The material design specification on Input Chips has a section labeled "Placement" that indicates that chips can appear in a horizontal scrollable list, which is slightly different but might work for us as well.

https://material.io/components/chips/#input-chips

Motivation 🔦

In our application design we have many multiple select auto complete filter boxes in a grid and we don't want the layout to be disrupted by displaying a lot of chips. We love your new Autocomplete component and this seemed like a useful feature or at least one that would make our designer happy.

@oliviertassinari oliviertassinari added the component: autocomplete This is the name of the generic UI component, not the React module! label Jan 8, 2020
@oliviertassinari
Copy link
Member

oliviertassinari commented Jan 11, 2020

The only approach I have seen related to this problem during my benchmark is:
Capture d’écran 2020-01-11 à 20 03 52
https://garden.zendesk.com/react-components/dropdowns/

@oliviertassinari oliviertassinari added the new feature New feature or request label Jan 11, 2020
@oliviertassinari oliviertassinari changed the title [Autocomplete] limit the number of rows of chips that a multiple item autocomplete will display [Autocomplete] Multiple with many options take too much vertical space Jan 11, 2020
@oliviertassinari oliviertassinari changed the title [Autocomplete] Multiple with many options take too much vertical space [Autocomplete] Multiple with many options take too much space Jan 11, 2020
@jaskerv
Copy link

jaskerv commented Feb 7, 2020

I found a temporary solution.

In your renderInput

 renderInput={ params => {
        const { InputProps, ...restParams } = params;
        const { startAdornment, ...restInputProps } = InputProps;
        return (
          <TextField
            { ...restParams }
            InputProps={ {
              ...restInputProps,
              startAdornment: (
                <div style={ {
                  maxHeight: <INSERT MAX HEIGHT>,
                  overflowY: 'auto',
                } }
                >
                  {startAdornment}
                </div>
              ),
            } }
          />
        );
      } }

Result:
image

Let me know if this works for you :)

If you found a way to replace maxHeight in px to maxHeight to rowsMax, let me know

@oliviertassinari
Copy link
Member

oliviertassinari commented Feb 22, 2020

Following up on #19137 (comment), I have tried a quick POC, it seems to be good enough. If somebody wants to complete it and open a pull request, it would be awesome.

Capture d’écran 2020-02-22 à 18 13 31

diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
index 463ff0f2f..85f080bc9 100644
--- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
+++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
@@ -338,6 +338,14 @@ const Autocomplete = React.forwardRef(function Autocomplete(props, ref) {
         />
       ));
     }
+
+    const filterMax = 2;
+    const more = startAdornment.length - filterMax;
+
+    if (filterMax && !focused && more > 0) {
+      startAdornment = startAdornment.splice(0, filterMax);
+      startAdornment.push(<span>{`+ ${more} more`}</span>)
+    }
   }

   const defaultRenderGroup = params => (

@oliviertassinari oliviertassinari added the ready to take Help wanted. Guidance available. There is a high chance the change will be accepted label Feb 22, 2020
@netochaves
Copy link
Contributor

Working on this issue.

@oliviertassinari
Copy link
Member

@mzbyszynski
Copy link
Author

mzbyszynski commented Mar 23, 2020

@oliviertassinari Yes limit tags as a great solution!
https://next.material-ui.com/components/autocomplete/#limit-tags

@msniezynski
Copy link

Is it possible to set maximum number of tags that will be visible when focused?

@oliviertassinari
Copy link
Member

oliviertassinari commented Apr 23, 2020

@mzbyszynski You can customize the component for doing such. There is a renderTags prop.

@logesh2496
Copy link

Is it possible to set maximum number of tags that will be visible when focused?

do we have support for this now?

@itsravenous
Copy link

@mzbyszynski You can customize the component for doing such.

Is there a documented example of this? I can't see anything in the docs, just the limitTags example. It would be fantastic to be able to have limitTags apply at all times, otherwise it makes it difficult to use this component in, for example, a toolbar as a filter.

@oliviertassinari oliviertassinari added waiting for 👍 Waiting for upvotes and removed ready to take Help wanted. Guidance available. There is a high chance the change will be accepted labels May 6, 2021
@oliviertassinari
Copy link
Member

@itsravenous The renderTags should do it. We could consider pushing the solution a step further. I can understand that https://material-ui.com/components/autocomplete/#limit-tags is not always enough.

It feels like the UX should be changed if it ever becomes an issue 🤔

@itsravenous
Copy link

Thanks @oliviertassinari - I'll check that out when I'm working tomorrow!

@itsravenous
Copy link

Sorry, @oliviertassinari, it was a while before I got back to this feature - your suggestion works great! For anyone else wanting to just get it working, this will show text labels for the first two selected options and a "+ n more" label when more than two are selected.

I wanted plain text labels, but you could also use the <Chip> component (as shown in the examples in the autocomplete docs)

      <Autocomplete
      // ...other props here
      renderTags={(value, getTagProps) => {
        const numTags = value.length;

        return (
          <Typography variant="body2">
            {value
              .slice(0, 2)
              .map((option, _) => option.title)
              .join(", ")}

            {numTags > 2 && ` +${numTags - 2} more`}
          </Typography>
        );
      }}

I do think an option to enable limitTags all the time would be really nice, but this is good enough for me 😃 thanks again!

@sfaman
Copy link

sfaman commented Jun 22, 2021

use condition on the renderTags to make it scrollable onFocus. Here is an Example
renderTags={(value, getTagProps) => {
if (this.state.showOwnersScroll) {
return (

{value.map((option, index) => ( 10 ? option.title.substring(0, 7) + "..." : option.title } size="small" {...getTagProps({ index })} /> ))}

);
} else {
return value.map((option, index) => (
10
? option.title.substring(0, 7) + "..."
: option.title
}
size="small"
{...getTagProps({ index })}
/>
));
}
}}
onFocus={() =>
this.setState({ showOwnersScroll: true })
}
onBlur={() =>
this.setState({ showOwnersScroll: false })
}

@hadasmaimon
Copy link

hadasmaimon commented Jun 30, 2021

Duplicate of #20782

@martin-trajanovski
Copy link

You can probably use something like this. I am limiting the tags to 1 in my example but you can adjust to your needs.

   renderTags={(value, getTagProps) => {
        const numTags = value.length;
        const limitTags = 1;

        return (
          <>
            {value.slice(0, limitTags).map((option, index) => (
              <Chip
                {...getTagProps({ index })}
                key={index}
                label={option.name}
              />
            ))}

            {numTags > limitTags && ` +${numTags - limitTags}`}
          </>
        );
      }}

@albert-benavent
Copy link

albert-benavent commented Feb 8, 2023

  Hi, I got here looking for a way to get the number of lines.
 My search filter is in position fixed and I want a responsive body control. I have a margin that changes depending on the 
 type of `screen.`
 For someone looking for something similar, I solved it thanks to the posts here:


      renderTags={(valuesChips, getTagProps) => {
      const numTags = valuesChips.length;
      const totalLines = Math.floor(numTags / (limitTags + 1)) + 1;
      let chipContainer = [];
      let startNextLine = 0;
      let finalNextLine = limitTags;

      for (let line = 0; line < totalLines; line++) {
        chipContainer.push(
          <div data-testid={`line${line}`} key={`line${line}`}>
            {options
              ? valuesChips.slice(startNextLine, finalNextLine).map((option, index) => {
                  const optionConverted = option.toString();
                  const position = parseInt(optionConverted) - 1;
                  return (
                    <Chip {...getTagProps({index})} key={options[position].label} label={options[position].label} />
                  );
                })
              : null}
          </div>
        );
        startNextLine += limitTags;
        finalNextLine += limitTags;
      }
      getNumberLinesComponent(totalLines);
      return chipContainer;
    }}

@JTtime
Copy link

JTtime commented Aug 13, 2024

limitTags is useful when it is on Blur. Main issue is when MUI is in focus

You can probably use something like this. I am limiting the tags to 1 in my example but you can adjust to your needs.

   renderTags={(value, getTagProps) => {
        const numTags = value.length;
        const limitTags = 1;

        return (
          <>
            {value.slice(0, limitTags).map((option, index) => (
              <Chip
                {...getTagProps({ index })}
                key={index}
                label={option.name}
              />
            ))}

            {numTags > limitTags && ` +${numTags - limitTags}`}
          </>
        );
      }}

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! new feature New feature or request waiting for 👍 Waiting for upvotes
Projects
None yet
Development

Successfully merging a pull request may close this issue.