ui
ui copied to clipboard
MUI Autocomplete dropdown doesn't respond on Shadcn Dialog
I have placed a MUI Autocomplete text input field on Dialog, the drop down scroll of MUI Autocomplete doesn't work on dialog. But in other places the dropdown works very well.
See the video and code below 👇👇
https://github.com/shadcn-ui/ui/assets/93305670/4a51c9e5-e63e-4058-b30d-83950ccc7d73
import React, { useState } from "react";
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import FreeSoloCreateOption from "@/components/FreeSoloCreateOption";
export default function MyComp() {
const [Time, setTime] = useState<string | undefined>("");
const [Meredium, setMeredium] = useState<string | undefined>("");
return (
<div>
<FreeSoloCreateOption setTime={setTime} setMeredium={setMeredium} />
<Dialog>
<DialogTrigger className="bg-green-500 mt-2">Open Dialog</DialogTrigger>
<DialogContent>
<FreeSoloCreateOption setTime={setTime} setMeredium={setMeredium} />
</DialogContent>
</Dialog>
</div>
);
}
import * as React from "react";
import TextField from "@mui/material/TextField";
import Autocomplete, { createFilterOptions } from "@mui/material/Autocomplete";
import { Button } from "@/components/ui/button";
import { ThemeProvider, createTheme } from "@mui/material/styles";
const filter = createFilterOptions<TimeSlotOptionType>();
import { useTheme } from "next-themes";
import dynamic from "next/dynamic";
type FreeSoloCreateOptionPropsType = {
setTime: React.Dispatch<React.SetStateAction<string | undefined>>;
setMeredium: React.Dispatch<React.SetStateAction<string | undefined>>;
};
function FreeSoloCreateOption({
setTime,
setMeredium,
}: FreeSoloCreateOptionPropsType) {
const { theme, setTheme } = useTheme();
const muiTheme = createTheme({
palette: {
mode: theme == "dark" ? "dark" : "light",
primary: {
main: "#9333ea",
},
secondary: {
main: "#9333ea",
},
},
});
const [value, setValue] = React.useState<TimeSlotOptionType | null>(null);
const [textError, settextError] = React.useState(false);
const [amOrPm, setAmOrPm] = React.useState("AM");
React.useEffect(() => {
setMeredium(amOrPm);
setTime(value?.time);
}, [amOrPm, setMeredium, setTime, value?.time]);
return (
<ThemeProvider theme={muiTheme}>
<div className="flex flex-row space-x-2 items-end justify-between">
<Autocomplete
value={value}
onChange={(event, newValue) => {
console.log("the newvalue", newValue, value);
if (typeof newValue === "string") {
setValue({
time: newValue,
});
} else if (newValue && newValue.inputValue) {
// Create a new value from the user input
console.log("here 2");
setValue({
time: newValue.inputValue,
});
} else {
console.log("here 3");
setValue(newValue);
}
}}
filterOptions={(options, params) => {
const filtered = filter(options, params);
const { inputValue } = params;
// Suggest the creation of a new value
const isExisting = options.some(
(option) => inputValue === option.time
);
if (inputValue !== "" && !isExisting) {
var newInputValue = "THIS_NEED_TO_BE_SET";
if (inputValue.length == 1 && parseInt(inputValue)) {
newInputValue = `${inputValue}:00`;
}
if (inputValue.length == 2 && parseInt(inputValue)) {
newInputValue = `${inputValue}:00`;
}
if (inputValue.length == 3 && parseInt(inputValue)) {
if (inputValue[0] == "0") {
const hours = inputValue.substring(0, 2);
const minutes = inputValue.substring(2);
newInputValue = `${hours}:0${minutes}`;
} else {
const hours = inputValue.substring(0, 1);
const minutes = inputValue.substring(1);
newInputValue = `0${hours}:${minutes}`;
}
}
if (inputValue.length == 4 && parseInt(inputValue)) {
const hours = inputValue.substring(0, 2);
const minutes = inputValue.substring(2, 4);
newInputValue = `${hours}:${minutes}`;
}
if (isValidTimeFormat(newInputValue)) {
settextError(false);
filtered.push({
inputValue: newInputValue,
time: `Add "${newInputValue}"`,
});
} else {
settextError(true);
}
}
return filtered;
}}
selectOnFocus
clearOnBlur
handleHomeEndKeys
id="free-solo-with-text-demo"
options={availableTimeSlot}
getOptionLabel={(option) => {
// Value selected with enter, right from the input
if (typeof option === "string") {
return option;
}
// Add "xxx" option created dynamically
if (option.inputValue) {
return option.inputValue;
}
// Regular option
return option.time;
}}
renderOption={(props, option) => (
<li {...props} key={option.time} className="text-sm mb-2">
{option.time}
</li>
)}
sx={{ width: 76 }}
freeSolo
renderInput={(params) => (
<TextField
{...params}
placeholder="hh:mm"
variant="standard"
className="placeholder:text-sm"
error={textError}
/>
)}
/>
<Button
variant="outline"
size={"sm"}
onClick={() =>
setAmOrPm((prevValue) => (prevValue === "AM" ? "PM" : "AM"))
}
>
{amOrPm}
</Button>
</div>
</ThemeProvider>
);
}
export default dynamic(() => Promise.resolve(FreeSoloCreateOption), {
ssr: false,
});
interface TimeSlotOptionType {
inputValue?: string;
time: string;
}
const availableTimeSlot: TimeSlotOptionType[] = [
{ time: "12:00" },
{ time: "12:15" },
{ time: "12:30" },
{ time: "12:45" },
{ time: "01:00" },
{ time: "01:15" },
{ time: "01:30" },
{ time: "01:45" },
{ time: "02:00" },
{ time: "02:15" },
{ time: "02:30" },
{ time: "02:45" },
{ time: "03:00" },
{ time: "03:15" },
{ time: "03:30" },
{ time: "03:45" },
{ time: "04:00" },
{ time: "04:15" },
{ time: "04:30" },
{ time: "04:45" },
{ time: "05:00" },
{ time: "05:15" },
{ time: "05:30" },
{ time: "05:45" },
{ time: "06:00" },
{ time: "06:15" },
{ time: "06:30" },
{ time: "06:45" },
{ time: "07:00" },
{ time: "07:15" },
{ time: "07:30" },
{ time: "07:45" },
{ time: "08:00" },
{ time: "08:15" },
{ time: "08:30" },
{ time: "08:45" },
{ time: "09:00" },
{ time: "09:15" },
{ time: "09:30" },
{ time: "09:45" },
{ time: "10:00" },
{ time: "10:15" },
{ time: "10:30" },
{ time: "10:45" },
{ time: "11:00" },
{ time: "11:15" },
{ time: "11:30" },
{ time: "11:45" },
];
function isValidTimeFormat(timeString: string) {
// Regular expression to match the hh:mm 12-hour format without AM/PM check
const regex = /^(0[1-9]|1[0-2]):[0-5][0-9]$/;
// Test the input string against the regular expression
return regex.test(timeString);
}
Hi, I had a similar issue, try adding "disablePortal" as a property in the autocomplete
<Autocomplete
disablePortal
/>
Hi, I had a similar issue, try adding "disablePortal" as a property in the autocomplete
<Autocomplete disablePortal />
Wow, I worked, Can I know the mechanism behind it @osorionicolas
I'm not sure 100% but it seems related with the use of portals. The other way should be to use portals in the shadcn Dialog but I didn't try it https://www.radix-ui.com/primitives/docs/components/dialog#api-reference
mui documentation:
Disable portal
To render the Popup where it's defined in the source, without using React portals, pass in the disablePortal
prop.
This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.