Skip to content

Commit 5fb8e19

Browse files
[material-ui][Autocomplete] Fix the options list being added to the DOM in freeSolo mode even when there are no options, causing style problems (#41300)
Co-authored-by: ZeeshanTamboli <zeeshan.tamboli@gmail.com>
1 parent a8ae789 commit 5fb8e19

File tree

2 files changed

+87
-64
lines changed

2 files changed

+87
-64
lines changed

packages/mui-material/src/Autocomplete/Autocomplete.js

Lines changed: 71 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,76 @@ const Autocomplete = React.forwardRef(function Autocomplete(inProps, ref) {
582582
const popperSlotProps = slotProps.popper ?? componentsProps.popper;
583583
const popupIndicatorSlotProps = slotProps.popupIndicator ?? componentsProps.popupIndicator;
584584

585+
const renderAutocompletePopperChildren = (children) => (
586+
<AutocompletePopper
587+
as={PopperComponent}
588+
disablePortal={disablePortal}
589+
style={{ width: anchorEl ? anchorEl.clientWidth : null }}
590+
ownerState={ownerState}
591+
role="presentation"
592+
anchorEl={anchorEl}
593+
open={popupOpen}
594+
{...popperSlotProps}
595+
className={clsx(classes.popper, popperSlotProps?.className)}
596+
>
597+
<AutocompletePaper
598+
ownerState={ownerState}
599+
as={PaperComponent}
600+
{...paperSlotProps}
601+
className={clsx(classes.paper, paperSlotProps?.className)}
602+
>
603+
{children}
604+
</AutocompletePaper>
605+
</AutocompletePopper>
606+
);
607+
608+
let autocompletePopper = null;
609+
if (!loading && groupedOptions.length > 0) {
610+
autocompletePopper = renderAutocompletePopperChildren(
611+
<AutocompleteListbox
612+
as={ListboxComponent}
613+
className={classes.listbox}
614+
ownerState={ownerState}
615+
{...otherListboxProps}
616+
{...ListboxProps}
617+
ref={combinedListboxRef}
618+
>
619+
{groupedOptions.map((option, index) => {
620+
if (groupBy) {
621+
return renderGroup({
622+
key: option.key,
623+
group: option.group,
624+
children: option.options.map((option2, index2) =>
625+
renderListOption(option2, option.index + index2),
626+
),
627+
});
628+
}
629+
return renderListOption(option, index);
630+
})}
631+
</AutocompleteListbox>,
632+
);
633+
} else if (loading && groupedOptions.length === 0) {
634+
autocompletePopper = renderAutocompletePopperChildren(
635+
<AutocompleteLoading className={classes.loading} ownerState={ownerState}>
636+
{loadingText}
637+
</AutocompleteLoading>,
638+
);
639+
} else if (groupedOptions.length === 0 && !freeSolo && !loading) {
640+
autocompletePopper = renderAutocompletePopperChildren(
641+
<AutocompleteNoOptions
642+
className={classes.noOptions}
643+
ownerState={ownerState}
644+
role="presentation"
645+
onMouseDown={(event) => {
646+
// Prevent input blur when interacting with the "no options" content
647+
event.preventDefault();
648+
}}
649+
>
650+
{noOptionsText}
651+
</AutocompleteNoOptions>,
652+
);
653+
}
654+
585655
return (
586656
<React.Fragment>
587657
<AutocompleteRoot
@@ -646,70 +716,7 @@ const Autocomplete = React.forwardRef(function Autocomplete(inProps, ref) {
646716
},
647717
})}
648718
</AutocompleteRoot>
649-
{anchorEl ? (
650-
<AutocompletePopper
651-
as={PopperComponent}
652-
disablePortal={disablePortal}
653-
style={{
654-
width: anchorEl ? anchorEl.clientWidth : null,
655-
}}
656-
ownerState={ownerState}
657-
role="presentation"
658-
anchorEl={anchorEl}
659-
open={popupOpen}
660-
{...popperSlotProps}
661-
className={clsx(classes.popper, popperSlotProps?.className)}
662-
>
663-
<AutocompletePaper
664-
ownerState={ownerState}
665-
as={PaperComponent}
666-
{...paperSlotProps}
667-
className={clsx(classes.paper, paperSlotProps?.className)}
668-
>
669-
{loading && groupedOptions.length === 0 ? (
670-
<AutocompleteLoading className={classes.loading} ownerState={ownerState}>
671-
{loadingText}
672-
</AutocompleteLoading>
673-
) : null}
674-
{groupedOptions.length === 0 && !freeSolo && !loading ? (
675-
<AutocompleteNoOptions
676-
className={classes.noOptions}
677-
ownerState={ownerState}
678-
role="presentation"
679-
onMouseDown={(event) => {
680-
// Prevent input blur when interacting with the "no options" content
681-
event.preventDefault();
682-
}}
683-
>
684-
{noOptionsText}
685-
</AutocompleteNoOptions>
686-
) : null}
687-
{groupedOptions.length > 0 ? (
688-
<AutocompleteListbox
689-
as={ListboxComponent}
690-
className={classes.listbox}
691-
ownerState={ownerState}
692-
{...otherListboxProps}
693-
{...ListboxProps}
694-
ref={combinedListboxRef}
695-
>
696-
{groupedOptions.map((option, index) => {
697-
if (groupBy) {
698-
return renderGroup({
699-
key: option.key,
700-
group: option.group,
701-
children: option.options.map((option2, index2) =>
702-
renderListOption(option2, option.index + index2),
703-
),
704-
});
705-
}
706-
return renderListOption(option, index);
707-
})}
708-
</AutocompleteListbox>
709-
) : null}
710-
</AutocompletePaper>
711-
</AutocompletePopper>
712-
) : null}
719+
{anchorEl ? autocompletePopper : null}
713720
</React.Fragment>
714721
);
715722
});

packages/mui-material/src/Autocomplete/Autocomplete.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2336,6 +2336,22 @@ describe('<Autocomplete />', () => {
23362336

23372337
expect(container.querySelector(`.${classes.endAdornment}`)).to.equal(null);
23382338
});
2339+
2340+
it('should not render popper when there are no options', () => {
2341+
render(
2342+
<Autocomplete
2343+
open
2344+
freeSolo
2345+
options={[]}
2346+
renderInput={(params) => <TextField {...params} />}
2347+
slotProps={{
2348+
popper: { 'data-testid': 'popperRoot' },
2349+
}}
2350+
/>,
2351+
);
2352+
const popper = screen.queryByTestId('popperRoot');
2353+
expect(popper).to.equal(null);
2354+
});
23392355
});
23402356

23412357
describe('prop: onChange', () => {

0 commit comments

Comments
 (0)