ui
ui copied to clipboard
Select Input Opening Automatically on Mobile Scroll
I have developed a web application using shadcn-ui and Next.js, featuring a registration page with a height exceeding the screen height, requiring users to scroll down to complete the full registration form.
The issue arises when users scroll on the page using a mobile phone. The 'select' input automatically triggers the touch finder, exhibiting oversensitivity. This results in the 'select' inputs auto-opening when users attempt to scroll down. It occurs when a user touches the 'select' input while scrolling. It's important to note that I am using the Shadcn-UI select without any custom modifications.
Is there any way to control the auto-opening of 'select' inputs when scrolling on mobile devices?
Live link for reference: https://x-project-design-system.vercel.app/reg
I noticed this, I'm looking for a solution to solve this behavior. Please, lemme know.
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.
hey there, is there any solution for this?
Any fixes for this yet?
As a workaround I added this component
const SelectWithTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root>
>(({ children, ...props }, ref) => {
const [isOpen, setIsOpen] = React.useState(false);
return (
<SelectPrimitive.Root open={isOpen} onOpenChange={setIsOpen} {...props} >
<SelectPrimitive.Trigger
onPointerDown={(e) => e.preventDefault()}
onClick={() => {
setIsOpen((state) => !state);
}}
ref={ref}
className={cn(
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
)}
>
{children}
<SelectPrimitive.Icon asChild>
<CaretSortIcon className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
</SelectPrimitive.Root>
);
});
SelectWithTrigger.displayName = "SelectWithTrigger";
Just make sure to export it and in your component replace
<Select>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent></SelectContent>
</Select>
With
<SelectWithTrigger>
<SelectValue />
<SelectContent></SelectContent>
</SelectWithTrigger>
As a workaround I added this component
const SelectWithTrigger = React.forwardRef< React.ElementRef<typeof SelectPrimitive.Trigger>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> >(({ children, ...props }, ref) => { const [isOpen, setIsOpen] = React.useState(false); return ( <SelectPrimitive.Root open={isOpen} onOpenChange={setIsOpen} {...props} > <SelectPrimitive.Trigger onPointerDown={(e) => e.preventDefault()} onClick={() => { setIsOpen((state) => !state); }} ref={ref} className={cn( "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", )} > {children} <SelectPrimitive.Icon asChild> <CaretSortIcon className="h-4 w-4 opacity-50" /> </SelectPrimitive.Icon> </SelectPrimitive.Trigger> </SelectPrimitive.Root> ); }); SelectWithTrigger.displayName = "SelectWithTrigger";Just make sure to export it and in your component replace
<Select> <SelectTrigger> <SelectValue /> </SelectTrigger> <SelectContent></SelectContent> </Select>With
<SelectWithTrigger> <SelectValue /> <SelectContent></SelectContent> </SelectWithTrigger>
This is working perfectly. Now the problem is solved. Thank you 🙌🏻
I don't know you guys, but I lose the accessibility.
This is happening because the FormControl that wraps the SelectValue is setting the ID attribute on the span, not on the button. Did someone catch that situation?
As a workaround I added this component
const SelectWithTrigger = React.forwardRef< React.ElementRef<typeof SelectPrimitive.Trigger>, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> >(({ children, ...props }, ref) => { const [isOpen, setIsOpen] = React.useState(false); return ( <SelectPrimitive.Root open={isOpen} onOpenChange={setIsOpen} {...props} > <SelectPrimitive.Trigger onPointerDown={(e) => e.preventDefault()} onClick={() => { setIsOpen((state) => !state); }} ref={ref} className={cn( "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1", )} > {children} <SelectPrimitive.Icon asChild> <CaretSortIcon className="h-4 w-4 opacity-50" /> </SelectPrimitive.Icon> </SelectPrimitive.Trigger> </SelectPrimitive.Root> ); }); SelectWithTrigger.displayName = "SelectWithTrigger";Just make sure to export it and in your component replace
<Select> <SelectTrigger> <SelectValue /> </SelectTrigger> <SelectContent></SelectContent> </Select>With
<SelectWithTrigger> <SelectValue /> <SelectContent></SelectContent> </SelectWithTrigger>
I was having similar issues, and this worked like a charm, thank you! added this to keep the pointer functionality on non-touch devices:
in SelectWithTrigger:
const isTouchDevice = () => {
return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
};
in <SelectPrimitive.Trigger:
onPointerDown={(e) => {
if (isTouchDevice()) {
e.preventDefault();
}
}}
onClick={() => {
if (isTouchDevice()) {
setIsOpen((state) => !state);
}
}}
still facing this, when user scroll it naturally touch the screen and move it, if it happened that touches the select input it will open and block everything
now no scroll, and input opens out of context ...