ui icon indicating copy to clipboard operation
ui copied to clipboard

Sheet portal still displaying content in the body

Open T3mpu5 opened this issue 1 year ago • 1 comments

I may have this wrong but does the SheetPortal allow the content to display within a div rather than the body? This is how I understand it from the Dialog docs. I'm passing the portal element through but it seems to still be mounting to the body.

return (
        domReady ?
            <div className='flex justify-end'>
                <Sheet>
                    <SheetTrigger asChild>
                        <Button variant="outline"><ShoppingCart className='pr-2' />£{cartData.total}</Button>
                    </SheetTrigger>
                    <SheetPortal container={portal}>
                        <SheetContent>
                            <SheetHeader>
                                <SheetTitle>Cart</SheetTitle>
                                <SheetDescription>
                                    Total: £{cartData.total}
                                </SheetDescription>
                            </SheetHeader>
                            {cartData.items.map(item => (
                                <div className='grid grid-cols-4 gap-4'>
                                    <div className='col-span-3'>
                                        <h3>{item.name}</h3>
                                        <p>Quantity: {item.quantity}</p>
                                        <p>£{item.price}</p>
                                    </div>
                                    <Button variant="destructive" className='col-span-1' onClick={(e) => handleDeleteCartItem(e, item)}>Delete</Button>
                                </div>
                            ))}
                            <SheetFooter>
                                <SheetClose asChild>
                                    <Button type="submit">Save changes</Button>
                                </SheetClose>
                            </SheetFooter>
                        </SheetContent>
                    </SheetPortal>
                </Sheet>
            </div>
            :
            null
    );
    ```
    
    The portal:
    ```
    const ShopUI: React.FC<ShopUIProps> = ({ shopData, cartData, setCartData }) => {
    const [container, setContainer] = useState<HTMLDivElement | null>(null);

    return (
        <div className="bg-zinc-700 p-4 rounded-lg shadow-lg max-w-3xl h-[80vh]">
            <div ref={setContainer}></div>
            <h3 className="text-lg text-white font-medium mb-2">SHOP</h3>
            <span>
                <Cart cartData={cartData} setCartData={setCartData} portal={container} />
            </span>
            <ScrollArea className='h-[85%] w-full pr-2 mt-2'>
                <div className="grid grid-cols-4 gap-4">
                    {shopData.items.map(item => (
                        <Item key={item.id} item={item} cartData={cartData} setCartData={setCartData} />
                    ))}
                </div>
            </ScrollArea>
        </div>
    );
}

Expected output: image

T3mpu5 avatar Jan 19 '24 15:01 T3mpu5

Could you reproduce the code? It would be much easier to help that way. But from the first glance I'd say that you should use useRef instead of useState and assign it to your div

V-Mokhun avatar Jan 22 '24 13:01 V-Mokhun

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.

shadcn avatar Feb 13 '24 23:02 shadcn

@T3mpu5 were you able to resolve this?

SahilMahadwar avatar Mar 11 '24 13:03 SahilMahadwar

No I didn't. I ended up using ant design instead

T3mpu5 avatar Mar 11 '24 13:03 T3mpu5

I had the same problem, passed the container element, like this: <SheetContent side="right" container={document.getElementById('YourDivID')}> and updated my shadcn component to add the container inside it (sheet.tsx) <SheetPortal container={props?.container}> sorry if this comment is useless, this was just my case

SukiDivine avatar Mar 28 '24 16:03 SukiDivine

Is there any solution to this issue? I tried different combinations following the Dialog docs (not working), however didn't succeed. If anybody solved that: I would be really happy to hear about it. @SukiDivine did you solve it? If yes, can you elaborate please?

LucasLoe avatar Jul 05 '24 18:07 LucasLoe

The portal works as expected, but the problem is caused by the styling.

const sheetVariants = cva(
  "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
  {
    variants: {
      side: {
        top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
        bottom:
          "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
        left: "inset-y-0 left-0  h-full w-3/4 border-r data-[state=closed]:slide-out-to-left  data-[state=open]:slide-in-from-left  sm:max-w-sm",
        right:
          "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
      },
    },
    defaultVariants: {
      side: "right",
    },
  },
);

Your SheetContent has the style "fixed inset-y-0", which makes it cover the full screen as if it were rendered in 'document.body'.

I had the same problem, passed the container element, like this: <SheetContent side="right" container={document.getElementById('YourDivID')}> and updated my shadcn component to add the container inside it (sheet.tsx) <SheetPortal container={props?.container}> sorry if this comment is useless, this was just my case

In my case, I achieved the desired result by adding the styles transform: translateZ(0) (tailwind: transform transform-z-0) to the container (#YourDivID). This creates a new stacking context and forces the element with fixed positioning to be contained within the specified container.

However, you might want to try solving the issue using more conventional methods. You could give the container a position: relative property and change the positioning of the element itself from fixed to absolute.

Both approaches can work, but the second method is generally more predictable and widely supported across browsers. Choose the one that best fits your specific use case and layout requirements.

evilive3000 avatar Aug 07 '24 12:08 evilive3000