htmlcsstailwind-cssshadcnui

How to make image scale to fit its container in TailwindCSS and ShadCN Dialog?


The image gets outside its parent bounds.

export function Dialog() {
    const src = 'https://placehold.co/1080x1920';
    return (
        <Dialog open={isOpen} onOpenChange={onClose}>
            <DialogContent className='flex max-h-[60%] min-h-[60%] max-w-[60%] min-w-[60%] flex-col bg-white'>
                <div className='flex grow gap-6'>
                    {/* Left column */}
                    <div className='flex flex-1 justify-center overflow-hidden rounded-lg bg-gray-200'>
                        {src && <img className='max-h-full max-w-full rounded-lg' src={src} />}
                    </div>

                    {/* Right Column */}
                    <div className='flex-1 space-y-4'>
                        <div className='text-xl font-semibold'>Title</div>
                        Some content
                    </div>
                </div>
            </DialogContent>
        </Dialog>
    );
}

How can I make sure it scales to fit its container while preserving aspect ratio?

I tried using different combinations of object-contain, percentages (h-[80%]), and fractions (h-3/4) but I didn't manage to accomplish it.


Update 1: The whole thing is wrapped in a shadcn Dialog, could that be the problem?


Update 2: I made it work with the suggestion from @rozsazoltan and using !max-w-fit in the DialogContainer (idea from here: How to change the size of a Shadcn dialog component?)


Solution

  • I modified the example because percentages are quite unstable values. I'm using rem to ensure the initial layout looks the same for everyone. As we can see, the image overflows:

    <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
    
    <body class="bg-gray-300">
      <div class="flex min-h-[7rem] max-h-[10rem] min-w-[7rem] max-w-[28rem] flex-col bg-white p-4">
        <div class="flex grow gap-6">
    
          <!-- Left column -->
          <div class="flex flex-1 justify-center overflow-hidden rounded-lg bg-gray-200">
            <img
              class="h-full max-h-full w-auto max-w-full rounded-lg object-contain"
              src="https://picsum.photos/1080/1920"
              alt="Preview"
            />
          </div>
    
          <!-- Right column -->
          <div class="flex-1 space-y-4">
            <div class="text-xl font-semibold">Title</div>
            <p>Some content</p>
          </div>
        </div>
      </div>
    </body>

    The parent's constraints do not directly affect the size of its flex children. You can hide the overflowing parts using overflow-hidden:

    <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
    
    <body class="bg-gray-300">
      <div class="flex min-h-[7rem] max-h-[10rem] min-w-[7rem] max-w-[28rem] flex-col bg-white p-4">
        <div class="flex grow gap-6 overflow-hidden"> <!-- HERE -->
          <!-- Left column -->
          <div class="flex flex-1 justify-center overflow-hidden rounded-lg bg-gray-200">
            <img
              class="h-full max-h-full w-auto max-w-full rounded-lg object-contain"
              src="https://picsum.photos/1080/1920"
              alt="Preview"
            />
          </div>
    
          <!-- Right column -->
          <div class="flex-1 space-y-4">
            <div class="text-xl font-semibold">Title</div>
            <p>Some content</p>
          </div>
        </div>
      </div>
    </body>

    All these flex containers, however, produce a somewhat strange result. We could solve it in a simpler way:

    <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
    
    <body class="bg-gray-300">
      <div class="flex min-h-[7rem] max-h-[10rem] min-w-[7rem] max-w-[28rem] gap-4 bg-white p-4 overflow-hidden rounded-lg">
        
        <!-- Image container -->
        <div class="flex-1 bg-gray-200 flex items-center justify-center overflow-hidden rounded-lg">
          <img 
            src="https://picsum.photos/1080/1920" 
            alt="Preview" 
            class="max-h-full max-w-full rounded-lg object-contain"
          />
        </div>
    
        <!-- Text content -->
        <div class="flex-1 space-y-4">
          <div class="text-xl font-semibold mb-2">Title</div>
          <p>Some content</p>
        </div>
    
      </div>
    </body>