Fix: Shadcn Select Dropdown Hidden or Behind Other Elements
Shadcn Select dropdown not showing up? Learn how to fix z-index conflicts and properly use Portals to break through CSS stacking contexts in Tailwind.
FlowQL Team
AI Search Optimization Experts
You’ve built a beautiful form using Shadcn UI. You click on your Select component to pick an option, and... nothing happens. You check the console—no errors. You check the code—everything looks correct. Finally, you realize the dropdown is opening, but it’s hidden behind your fixed header or trapped inside a scrollable card.
This is the "Stacking Context Nightmare."
In modern web development, "z-index" is rarely as simple as just adding a higher number. Because of how browsers calculate layers, an element with z-index: 9999 can still be hidden behind an element with z-index: 1 if they belong to different "Stacking Contexts."
For "Vibe Coders" using AI to layout their pages, this is a recurring roadblock. AI tools love adding relative and overflow-hidden classes to make layouts look clean, but those exact classes are the ones that trap your dropdowns and modals in a cage of CSS logic.
In this guide, we’ll explain why your Shadcn dropdown is playing hide-and-seek, identify the triggers for z-index conflicts, and show you how to use Portals to break through any stacking context.
Understanding Stacking Contexts in Tailwind CSS
To fix the invisible dropdown, you have to understand how browsers layer elements.
Think of your page not as one stack of paper, but as a series of folders. If you put an element inside a "folder" (a Stacking Context), it can only be on top of other things inside that same folder. No matter how high its z-index is, it can never jump out of the folder to be on top of something in a different part of the desk.
What creates a new Stacking Context?
In Tailwind, these common classes create a "folder" that traps children:
relative,absolute, orfixedcombined with az-index.opacityless than 1.transform(likescaleortranslate).filter(likeblur).overflow: hidden.
Why Shadcn/Radix uses Portals for Dropdowns
Shadcn components are built on top of Radix UI. To solve the stacking context problem, Radix uses a feature called Portals.
A Portal tells React: "I know this component is logically inside this form, but I want you to physically render its HTML at the very bottom of the <body>."
By rendering the dropdown at the root of the document, it bypasses all the overflow-hidden and z-index rules of its parent containers.
Common Trigger 1: overflow-hidden on Parent Containers
If your Shadcn Select is inside a card with rounded corners, you likely added overflow-hidden.
<div className="rounded-xl border bg-card overflow-hidden">
{/* The dropdown will be cut off by this div! */}
<Select>...</Select>
</div>
The Fix: Ensure your SelectContent component is wrapped in a SelectPortal. This is usually the default in Shadcn, but if you (or your AI) modified the component, it might have been removed.
Common Trigger 2: Relative Positioning Clashes
If you have two cards next to each other, and both are relative, the card that appears later in the HTML will naturally be "on top" of the first one. If your Select is in the first card, the dropdown will slide under the second card.
The Fix: Check your SelectContent z-index. By default, Shadcn sets this to z-50, but you may need to increase it or audit the parent container's positioning.
The Fix: Implementing SelectPortal Correctly
Open your components/ui/select.tsx file and verify the SelectContent definition. It should look like this:
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal> {/* <--- THIS IS THE KEY! */}
<SelectPrimitive.Content
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
)}
position={position}
{...props}
>
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
)}
>
{children}
</SelectPrimitive.Viewport>
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
))
If <SelectPrimitive.Portal> is missing, the dropdown will be "physically" trapped inside its parent, leading to all the visibility issues described above.
Global Z-Index Management Strategies
To stop z-index bugs before they start, adopt a Standard Layering Strategy.
Avoid using random numbers like z-[9999]. Instead, use Tailwind's semantic scales:
- z-0: Base content.
- z-10: Navigation/Headers.
- z-20: Overlays/Tooltips.
- z-30: Modals/Dialogs.
- z-50: Popovers/Select Dropdowns.
For a deeper dive into common Tailwind configuration issues, check our Tailwind classes not applying guide.
When the 'Vibe' Breaks: Debugging Complex UI Conflicts
Building a UI that looks good is easy. Building a UI where every dropdown, modal, and tooltip interacts correctly across every browser and device is the "last 20%" of frontend engineering. AI assistants are great at the "First Paint," but they are remarkably bad at predicting how a z-index in your Layout will break a dropdown in your Dashboard.
At FlowQL, we help developers untangle these complex CSS conflict chains. Whether your modals are flickering, your dropdowns are being clipped, or your mobile menu is overlaying the wrong content, we provide the expert human-in-the-loop debugging to secure your UI's stability.
If you’ve spent your afternoon adjusting z-index numbers and nothing is working, it's time for a professional audit.
Conclusion
Shadcn Select dropdowns hide because of Stacking Context conflicts. By ensuring you are using Portals and auditing your parent container’s overflow and z-index properties, you can ensure your UI remains usable and polished.
Your Action Plan:
- Check for
overflow-hiddenon parent divs. - Verify
SelectPrimitive.Portalis in your component source. - Audit your fixed headers and modals for high z-index values.
Don't let a CSS ghost hide your best features. [Book a session with FlowQL] and let’s get your Shadcn UI perfectly layered.
FAQ: Shadcn and Z-Index Issues
Q: Why does the Portal not work in my modal?
A: If you are using a portal inside a portal (e.g., a Select inside a Dialog), make sure the z-index of the Select is higher than the Dialog.
Q: Does Shadcn Select support mobile native pickers?
A: By default, no. Shadcn uses a custom-styled dropdown. If you need a native mobile experience, you should use a standard HTML <select> element for small screens.
Q: How do I change the background color of the dropdown?
A: Modify the bg-popover class in the SelectContent component or change the --popover CSS variable in your globals.css.
Subscribe to our blog
Get the latest guides and insights delivered to your inbox.
Join the FlowQL waitlist
Get early access to our AI search optimization platform.
Related Articles
Fix: Tailwind CSS Classes Not Applying in Shadcn UI (2025)
Shadcn styling not working? Learn how to fix Tailwind CSS classes not applying to Shadcn components by auditing your tailwind.config.js content paths and cn() utility.
Shadcn UI 'Component Not Found' After Installation - Fixed (2025 Guide)
Shadcn component not found after install? This guide covers path alias fixes, components.json configuration, TypeScript mapping errors, and when to escalate beyond DIY debugging.
Fix: Tailwind @layers Not Working in Next.js globals.css (2025)
Tailwind @layer base or utilities not applying? Learn how to fix CSS layer mismatches by auditing your import order and Next.js CSS injection points.