shadcn-ui / ui

Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.
https://ui.shadcn.com
MIT License
69.13k stars 4.1k forks source link

[bug]: Layout Shift when Opening Select Component #977

Open alwalxed opened 1 year ago

alwalxed commented 1 year ago

https://github.com/shadcn-ui/ui/assets/119763173/ce8560fa-2d8f-4970-aaa8-0dfb8d40eebe

rollakal commented 1 year ago

Can you provide a sandbox with the issue? Do you have overflow rules on <html> rather than <body>?

alwalxed commented 1 year ago

Can you provide a sandbox with the issue? Do you have overflow rules on <html> rather than <body>?

Layout screenshot

Page screenshot (1)

Component screenshot (2)

rollakal commented 1 year ago

Try to remove overflow-x-hidden on <html>. Cant really reproduce the issue from screenshots. So i guess that could fix it.

alwalxed commented 1 year ago

Try to remove overflow-x-hidden on <html>. Cant really reproduce the issue from screenshots. So i guess that could fix it.

I actually added it when you commented on your previous comment to test it out, but it didn't work. It's kinda puzzling.

rollakal commented 1 year ago

Can you share a sandbox?

cheng-dai commented 1 year ago

I had the same issue, removing the class of body to a new div under the body solved the issue.

ahmedivy commented 1 year ago

@chengd42 thanks bro, that also solves my problem with dialog.

dim-anis commented 1 year ago

@chengd42 thanks!

dan5py commented 1 year ago

@ahmedivy this issue can be closed as completed. @shadcn

ivanhueso commented 1 year ago

I have the same issue and this is my code:

   <html lang="en">
      <body>
        {children}
      </body>
    </html>
  )
voidoperator commented 1 year ago

if for some reason anyone wants to solve this without moving all of body's classes into a new child div you can add "min-w-full" to body. added the ! for overkill

body { @apply !min-w-full; }

alwalxed commented 1 year ago

It seems like the solution provided above didn't resolve my issue. Here's what worked for me: I found that the problem was caused by the container of the select component being centered using mx-auto. Instead, I fixed it by making it fixed and centrally positioned using the left and right properties. It's not the cleanest solution, but it did the job.

ssssylassss commented 11 months ago

https://github.com/shadcn-ui/ui/assets/125253203/071e7c51-4e3b-459f-a22d-87bd66c20f0d

i get the same issue but more drastic.

danetreab commented 11 months ago

c4bee2075a0940265dce10d721b22300.mp4 i get the same issue but more drastic.

I get the same problem, i able to work around it, below are the example.

<div className='items-center flex my-8 container'> // parent container
      <p>Content</p>
      <div className='flex gap-4 flex-1 justify-end items-center'> // (dropdown component) in className don't forget "flex-1"
                        <ModeToggle />
                        <DropdownMenu>
                            <DropdownMenuTrigger>
                                <Avatar>
                                    <AvatarImage src="https://github.com/shadcn.png" />
                                    <AvatarFallback>CN</AvatarFallback>
                                </Avatar>
                            </DropdownMenuTrigger>
                            <DropdownMenuContent align='end'>
                                <DropdownMenuLabel>My Account</DropdownMenuLabel>
                                <DropdownMenuSeparator />
                                <DropdownMenuItem>Profile</DropdownMenuItem>
                                <DropdownMenuItem>Billing</DropdownMenuItem>
                                <DropdownMenuItem>Team</DropdownMenuItem>
                                <DropdownMenuItem>Subscription</DropdownMenuItem>
                            </DropdownMenuContent>
                        </DropdownMenu>
          </div>
</div>
Jervx commented 11 months ago

What I think causes this is radix ui which is used by shadcn, it altering the styling, this causes to hide all other elements scrollbar that causes their parent to take the size where the scrollbar is located. In this case the body which style is set to w-full ( take all available space ). So whenever the scrollbar disappears, the body will take that space that's why it shifts

There's couple of solutions I tested out myself, but this one works for me

Make the body width to viewport and hide the overflow horizontally

html,body,:root { height: 100%; }


- layout.tsx
```tsx
<body className="w-screen overflow-x-hidden ...otherstyles">

</body>

I also changed my custom navbar w-screen as it is also affected by the shifting

Here's gif of what I experience & the fix

https://github.com/shadcn-ui/ui/assets/48374007/3dfab276-94d3-4f03-980f-df45fd44f6b0

I hope this helps 😄

andp97 commented 10 months ago

I encountered the same issue and was able to resolve it by removing all classes from the body element and adding a child div:

BEFORE:

<html>
    <body className='container mx-auto'>
         {children}
    </body>
</html>

AFTER:

<html>
    <body>
        <div className='container mx-auto'>
             {children}
        </div>
    </body>
</html>
AnikKDev commented 10 months ago

@rollakal solved the issue man. thanks much.

Anishali2 commented 9 months ago

I have the same issue and this is my code:

   <html lang="en">
      <body>
       <div> {children} </div>
      </body>
    </html>
  )

make another div in body and pass children and also remove the body css from global css or your main file

alexqs96 commented 6 months ago

that worked for me, that data attribute is added once the select is open

body[data-scroll-locked]{
  min-width: 100%;
}
fernandortec commented 6 months ago

Does anyone have a plain CSS solution? I'm not using Next, I'm using Vite, and my application isn't wrapped in a single-body tag. If there's no other solution I'll do that, but I don't feel like adding layouts JUST for this yk?

alexqs96 commented 6 months ago

Does anyone have a plain CSS solution? I'm not using Next, I'm using Vite, and my application isn't wrapped in a single-body tag. If there's no other solution I'll do that, but I don't feel like adding layouts JUST for this yk?

if u are using vite try to add this to your css

body[data-scroll-locked] #root{ min-width: 100%; }

fernandortec commented 6 months ago

Does anyone have a plain CSS solution? I'm not using Next, I'm using Vite, and my application isn't wrapped in a single-body tag. If there's no other solution I'll do that, but I don't feel like adding layouts JUST for this yk?

if u are using vite try to add this to your css

body[data-scroll-locked] #root{ min-width: 100%; }

the layout shift still appears, its because when i close the select, the vertical scrolling of the page appears, i need to find a way to remove all vertical scrolls when dialog is open

Christianey commented 6 months ago

Does anyone have a plain CSS solution? I'm not using Next, I'm using Vite, and my application isn't wrapped in a single-body tag. If there's no other solution I'll do that, but I don't feel like adding layouts JUST for this yk?

if u are using vite try to add this to your css body[data-scroll-locked] #root{ min-width: 100%; }

the layout shift still appears, its because when i close the select, the vertical scrolling of the page appears, i need to find a way to remove all vertical scrolls when dialog is open

Please have you been able to fix this? I'm facing the same issue.

fernandortec commented 6 months ago

Does anyone have a plain CSS solution? I'm not using Next, I'm using Vite, and my application isn't wrapped in a single-body tag. If there's no other solution I'll do that, but I don't feel like adding layouts JUST for this yk?

if u are using vite try to add this to your css body[data-scroll-locked] #root{ min-width: 100%; }

the layout shift still appears, its because when i close the select, the vertical scrolling of the page appears, i need to find a way to remove all vertical scrolls when dialog is open

Please have you been able to fix this? I'm facing the same issue.

I haven't, yet, I believe by the end of this week I'll try to debug it and maybe fix it, but I'm still left with no answers

Christianey commented 6 months ago

Okay. I've spent quite a while on this and I can't really figure out what is wrong. I just noticed that if I remove some elements from the page it works fine. Please share your solution if you fix it. Thanks.

IvarK commented 6 months ago

I have the same issue. I have a Select component inside Dialog, when I open the dialog, the data-scroll-locked property is added to the body. When I open the select component, the same property seems to be added, but when I close the select component, it removes the property, even when the dialog is still open.

developedbygeo commented 5 months ago

I faced a similar issue, but with vertical layout shift. The cause was what @IvarK mentions - the rule body[data-scroll-locked] that is being applied once it opens. Overriding the vertical padding there fixed it for me.

dmaslan commented 5 months ago

I have the same issue. I have a Select component inside Dialog, when I open the dialog, the data-scroll-locked property is added to the body. When I open the select component, the same property seems to be added, but when I close the select component, it removes the property, even when the dialog is still open.

I'm experiencing this exact issue. Did you find a solution?

7hourspg commented 4 months ago

Pass something like this in comp if you are facing the same issue with dropdown

<DropdownMenu modal={false}>

For select you can do this

html {
  overflow-x: hidden;
}
YO-SC commented 4 months ago

Ideally we won't need to worry about layout shifts. Hopefully this won't be the case in the future :D

EliyahuCohen commented 4 months ago

I encountered the same issue and was able to resolve it by removing all classes from the body element and adding a child div:

BEFORE:

<html>
    <body className='container mx-auto'>
         {children}
    </body>
</html>

AFTER:

<html>
    <body>
        <div className='container mx-auto'>
             {children}
        </div>
    </body>
</html>

Perfect , worked for me , thank you

diegoulloao commented 4 months ago

I encountered the same issue and was able to resolve it by removing all classes from the body element and adding a child div:

BEFORE:

<html>
    <body className='container mx-auto'>
         {children}
    </body>
</html>

AFTER:

<html>
    <body>
        <div className='container mx-auto'>
             {children}
        </div>
    </body>
</html>

worked for me

RemyJouni commented 4 months ago
w-screen overflow-x-hidden

This is the best and cleanest solution, I only had to use w-screen in the body.

The second solution of moving the classes from the body to a div underneath it is not good for SEO.

vidhanshu commented 3 months ago

if for some reason anyone wants to solve this without moving all of body's classes into a new child div you can add "min-w-full" to body. added the ! for overkill

body { @apply !min-w-full; }

Thanks @voidoperator this resolved my issue

coding-billi commented 3 months ago

just put modal={false} on the <DropdownMenu> like this, same for select! <DropdownMenu modal={false}>

arunkundu45 commented 3 months ago

@coding-billi but what about when you are using a Dialog and need's to use modal={true} ..?

Dey11 commented 3 months ago

Pass something like this in comp if you are facing the same issue with dropdown

<DropdownMenu modal={false}>

For select you can do this

html {
  overflow-x: hidden;
}

thanks a lot mate! this is the one that worked for me. by applying this the scroll wheel doesnt get hidden even when i open the dropdown menu and thats what was causing the layout shift

CollinsKippy commented 2 months ago

if for some reason anyone wants to solve this without moving all of body's classes into a new child div you can add "min-w-full" to body. added the ! for overkill

body { @apply !min-w-full; }

This one worked for me!

lumpinif commented 2 months ago

Pass something like this in comp if you are facing the same issue with dropdown

<DropdownMenu modal={false}>

For select you can do this

html {
  overflow-x: hidden;
}

this one is a kill

kubilaybzk commented 2 months ago
<html lang="en" className=''>
      <body className={`${inter.className}  w-screen overflow-x-hidden`}>

              {children}

      </body>
    </html>

This one worked for me!

ZakKa89 commented 1 month ago

In my case the layout shift was caused because the vertical scrollbar was removed, causing horizontal layout shift. Here is a solution for that:

I am using the sveltekit shadcn version, but something like this should work for all shadcn in general

<DropdownMenu.Root preventScroll={false}>
jlopezvaldez commented 1 month ago

@andp97 worked for me ty ty

Mahmoud-D commented 1 month ago

Pass something like this in comp if you are facing the same issue with dropdown

<DropdownMenu modal={false}>

For select you can do this

html {
  overflow-x: hidden;
}

Thanks for this solution, it was really helpful 👍

redeemefy commented 1 month ago

this is what worked for me

    <html lang="en">
      <body className={cn('font-sans', inter.variable)}>
        <div className={cn('min-h-screen bg-background antialiased flex flex-col px-4')}>
          <ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
            {children}
          </ThemeProvider>
        </div>
      </body>
    </html>

I had to keep the inter.variable and the font-sans in the body because otherwise was changing font all over the place.

rendi12345678 commented 1 month ago

screenshot-20240810-074025Z-all just add w-svw or w-screen

Lexachoc commented 1 month ago

That really drives me crazy!!!!

I had already tried many solutions above, but not single solution could solve the problem until I tried a combination of solutions.

  1. set modal={false}
<Select modal={false}
...
</Select>
  1. css
    
    html {
    overflow-x: hidden;
    }

body[data-scroll-locked] { min-width: 100%; }



No layout shift and missing of vertical scrollbar anymore for my case.
I think it really depends on the case. But thanks for all the solutions!
shobhitexe commented 1 month ago

if for some reason anyone wants to solve this without moving all of body's classes into a new child div you can add "min-w-full" to body. added the ! for overkill

body { @apply !min-w-full; }

Thanks a ton! it worked

mikeyxb commented 2 weeks ago

I also encountered this issue with Select and Drowpdown, the issue was my padding on the body, adding important to these CSS properties resolved the issue for me