csstailwind-cssoverflow

Output window using overflow doesn't behave as expected on tailwind css


I got this initial design with my Raw output that looks like this: image of the original design

It takes up the whole width just as intended. The problem is that when it has content and the content is too long it breaks the design and gets too long: image of the broken design in terms of height and width

As you can see, the width is too long and it destroys the design. The overflow of the Raw output breaks the design. This is my code:

UPDATE: This is my index.css:

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  /* UNI STYLE */
  * {
    @apply m-0 p-0;
  }

  html,
  body,
  #root {
    @apply h-full;
  }

  /* TOP NAVIGATION */

  .mobile-navigation {
    @apply flex items-center justify-between bg-gray-800 p-4 text-white md:hidden;
  }

  .mobile-logo {
    @apply text-lg font-bold;
  }

  .mobile-button {
    @apply z-50  focus:outline-none;
  }
  /* EOL - TOP NAVIGATION */

  /*  SIDEBAR CSS */
  .sidebar {
    @apply flex h-screen flex-col md:flex-row;
  }

  .logo {
    @apply text-center font-bold sm:p-3 md:p-6 md:text-xl;
  }

  nav ul .links {
    @apply hover:bg-test block px-6  py-4;
  }

  nav ul .mobile-links {
    @apply hover:bg-test block  px-4 py-4  text-center hover:text-fountainBlue;
  }

  .active {
    font-weight: bold;
    color: #86a3da;
  }
}

Update: This is the SideNavigationLayout.tsx

import { Link, routes } from '@redwoodjs/router'
import { useState } from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faBars, faTimes } from '@fortawesome/free-solid-svg-icons'
import { useLocation } from '@redwoodjs/router'

type SideNavigationLayoutProps = {
  children?: React.ReactNode
}

const SideNavigationLayout = ({ children }: SideNavigationLayoutProps) => {
  const [menuOpen, setMenuOpen] = useState(false)
  const location = useLocation()

  const toggleMenu = () => {
    setMenuOpen(!menuOpen)
  }

  return (
    <div className="sidebar">
      <header className="mobile-navigation">
        <h1 className="mobile-logo">FantaTech - Gen-AI</h1>
        <button
          onClick={toggleMenu}
          className={`mobile-button 
              ${menuOpen ? 'text-gray-800' : 'text-white'}`}
          aria-label="Toggle menu"
        >
          <FontAwesomeIcon
            icon={menuOpen ? faTimes : faBars}
            className="h-6 w-6"
          />
        </button>
      </header>

      <aside
        className={`fixed left-0 top-0 z-40 h-full w-full transform pt-6 transition-transform duration-300 md:static md:z-auto md:h-auto md:w-auto md:translate-x-0 md:bg-gray-800 md:pt-3 md:text-white
                    ${menuOpen ? 'translate-x-0 bg-gray-100 text-gray-800' : '-translate-x-full bg-gray-800 text-white'}`}
      >
        <div className="logo">
          <h2>FantaTech - Gen-AI</h2>
        </div>
        <nav className="mt-3">
          <ul>
            <Link
              className={`${menuOpen ? 'mobile-links' : 'links'} ${location.pathname === routes.scrape() ? 'active' : ''}`}
              to={routes.scrape()}
            >
              <li>Scrape</li>
            </Link>
            <Link
              className={`${menuOpen ? 'mobile-links' : 'links'} ${location.pathname === routes.crawl() ? 'active' : ''}`}
              to={routes.crawl()}
            >
              <li>Crawl</li>
            </Link>
            <Link
              className={`${menuOpen ? 'mobile-links' : 'links'} ${location.pathname === routes.pdfUpload() ? 'active' : ''}`}
              to={routes.pdfUpload()}
            >
              <li>PDF Upload</li>
            </Link>
          </ul>
        </nav>
      </aside>

      <main className="flex-1">{children}</main>

      {/* Overlay for mobile menu */}
      {/* {menuOpen && (
        <div
          className="fixed inset-0 z-30 bg-black bg-opacity-50 md:hidden"
          onClick={toggleMenu}
        ></div>
      )} */}
    </div>
  )
}

export default SideNavigationLayout

ScrapePage.tsx

const ScrapePage = () => {
  const [searchInput, setSearchInput] = useState('')
  const [outputData, setOutputData] = useState('')
  const [isLoading, setIsLoading] = useState(false)
  const [isSubmitted, setIsSubmitted] = useState(false)

  const handleSubmit = async () => {
    setIsLoading(true)
    setIsSubmitted(true)
    try {
      const apiEndpoint = 'http://localhost:8087/simplify'

      const response = await fetch(apiEndpoint, {
        method: 'POST',
        body: JSON.stringify({ url: searchInput }),
      })

      if (!response.ok) {
        throw new Error('Failed to fetch results')
      }

      const text = await response.text()
      setOutputData(text)
      // setOutputData(JSON.stringify(json, null, 2));
    } catch (error) {
      setOutputData(`Error: ${error.message}`)
    } finally {
      setIsLoading(false)
    }
  }

  const handleInputChange = (event) => {
    setSearchInput(event.target.value)
    setIsSubmitted(false)
  }

  return (
    <>
      <Metadata title="Scrape" description="Scrape page" />

      <div className="h-screen overflow-auto bg-gray-100 p-9">
        <SearchForm
          searchInput={searchInput}
          isLoading={isLoading}
          onInputChange={handleInputChange}
          onSubmit={handleSubmit}
        />

        <div className="flex w-full flex-col">
          <div className="mt-4">
            <h2 className="text-l mb-2 text-gray-700">
              <strong>Raw Output</strong>
            </h2>
            <RawOutput input={isSubmitted ? outputData : searchInput} />
          </div>

          <div className="mt-8">
            <h2 className="text-l mb-2 text-gray-700">
              <strong>Extract</strong>
            </h2>
            <ExtractOutput />
          </div>
        </div>
      </div>
    </>
  )
}

export default ScrapePage

export default ScrapePage

RawOutput.tsx

const RawOutput = ({ input }: Props) => {
  return (
    <div className="rounded-md border border-gray-300 bg-gray-50 p-4">
      <pre className="overflow-auto text-gray-800">
        {input || 'No input provided'}
      </pre>
    </div>
  )
}

When I apply overflow-auto on the parent div, it doesn't break the design in terms of height: image of the container with correct height

But in terms of width the design is broken: image of the container with broken design using width

Basically my goal is just that the width of the Raw output will be fixed with screen size and will only have a scroll if it's too long. Perfect example for it is the design like here in the stackoverflow when the code being shared is too long: image of the goal of this inquiry


Solution

  • You'd want to apply min-width: 0 to the <main> element in SideNavigationLayout.tsx:

    tailwind.config = {
      theme: {
        extend: {
            backgroundColor: {
            test: 'slate',
          },
            textColor: {
            fountainBlue: 'blue',
          }
        }
      }
    }
    <script src="https://cdn.tailwindcss.com/3.4.16"></script>
    <style type="text/tailwindcss">
    @layer components {
      /* UNI STYLE */
      * {
        @apply m-0 p-0;
      }
    
      html,
      body,
      #root {
        @apply h-full;
      }
    
      /* TOP NAVIGATION */
    
      .mobile-navigation {
        @apply flex items-center justify-between bg-gray-800 p-4 text-white md:hidden;
      }
    
      .mobile-logo {
        @apply text-lg font-bold;
      }
    
      .mobile-button {
        @apply z-50  focus:outline-none;
      }
      /* EOL - TOP NAVIGATION */
    
      /*  SIDEBAR CSS */
      .sidebar {
        @apply flex h-screen flex-col md:flex-row;
      }
    
      .logo {
        @apply text-center font-bold sm:p-3 md:p-6 md:text-xl;
      }
    
      nav ul .links {
        @apply hover:bg-test block px-6  py-4;
      }
    
      nav ul .mobile-links {
        @apply hover:bg-test block  px-4 py-4  text-center hover:text-fountainBlue;
      }
    
      .active {
        font-weight: bold;
        color: #86a3da;
      }
    }
    </style>
    
    <div id="app"></div>
    
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <script type="importmap">
      {
        "imports": {
          "@fortawesome/free-solid-svg-icons": "https://esm.sh/@fortawesome/free-solid-svg-icons",
          "@fortawesome/react-fontawesome": "https://esm.sh/@fortawesome/react-fontawesome",
          "react": "https://esm.sh/react@18",
          "react-dom/client": "https://esm.sh/react-dom@18/client"
        }
      }
    </script>
    <script type="text/babel" data-type="module">
      import React from "react";
      import client from "react-dom/client";
    
      const RawOutput = ({ input }) => {
        return (
          <div className="rounded-md border border-gray-300 bg-gray-50 p-4">
            <pre className="overflow-auto text-gray-800">
              {input || 'No input provided'}
            </pre>
          </div>
        )
      }
      
      const SearchForm = () => <div>SearchForm</div>
      const ExtractOutput = () => <div>ExtractOutput</div>
    
      const ScrapePage = () => {
        const [searchInput, setSearchInput] = useState('')
        const [outputData, setOutputData] = useState(Array(10).fill().map(() => window.crypto.randomUUID()).join('-'))
        const [isLoading, setIsLoading] = useState(false)
        const [isSubmitted, setIsSubmitted] = useState(true)
    
        const handleSubmit = async () => {
          setIsLoading(true)
          setIsSubmitted(true)
          try {
            const apiEndpoint = 'http://localhost:8087/simplify'
    
            const response = await fetch(apiEndpoint, {
              method: 'POST',
              body: JSON.stringify({ url: searchInput }),
            })
    
            if (!response.ok) {
              throw new Error('Failed to fetch results')
            }
    
            const text = await response.text()
            setOutputData(text)
            // setOutputData(JSON.stringify(json, null, 2));
          } catch (error) {
            setOutputData(`Error: ${error.message}`)
          } finally {
            setIsLoading(false)
          }
        }
    
        const handleInputChange = (event) => {
          setSearchInput(event.target.value)
          setIsSubmitted(false)
        }
    
        return (
          <>
            {/*<Metadata title="Scrape" description="Scrape page" />*/}
    
            <div className="h-screen overflow-auto bg-gray-100 p-9">
              <SearchForm
                searchInput={searchInput}
                isLoading={isLoading}
                onInputChange={handleInputChange}
                onSubmit={handleSubmit}
              />
    
              <div className="flex w-full flex-col">
                <div className="mt-4">
                  <h2 className="text-l mb-2 text-gray-700">
                    <strong>Raw Output</strong>
                  </h2>
                  <RawOutput input={isSubmitted ? outputData : searchInput} />
                </div>
    
                <div className="mt-8">
                  <h2 className="text-l mb-2 text-gray-700">
                    <strong>Extract</strong>
                  </h2>
                  <ExtractOutput />
                </div>
              </div>
            </div>
          </>
        )
      }
      
      // import { Link, routes } from '@redwoodjs/router'
      import { useState } from 'react'
      import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
      import { faBars, faTimes } from '@fortawesome/free-solid-svg-icons'
      // import { useLocation } from '@redwoodjs/router'
    
      const Link = props => <a {...props}/>;
      const routes = {
        crawl: () => {},
        pdfUpload: () => {},
        scrape: () => {},
      };
      const useLocation = () => ({});
    
      const SideNavigationLayout = ({ children }) => {
        const [menuOpen, setMenuOpen] = useState(false)
        const location = useLocation()
    
        const toggleMenu = () => {
          setMenuOpen(!menuOpen)
        }
    
        return (
          <div className="sidebar">
            <header className="mobile-navigation">
              <h1 className="mobile-logo">FantaTech - Gen-AI</h1>
              <button
                onClick={toggleMenu}
                className={`mobile-button 
                    ${menuOpen ? 'text-gray-800' : 'text-white'}`}
                aria-label="Toggle menu"
              >
                <FontAwesomeIcon
                  icon={menuOpen ? faTimes : faBars}
                  className="h-6 w-6"
                />
              </button>
            </header>
    
            <aside
              className={`fixed left-0 top-0 z-40 h-full w-full transform pt-6 transition-transform duration-300 md:static md:z-auto md:h-auto md:w-auto md:translate-x-0 md:bg-gray-800 md:pt-3 md:text-white
                          ${menuOpen ? 'translate-x-0 bg-gray-100 text-gray-800' : '-translate-x-full bg-gray-800 text-white'}`}
            >
              <div className="logo">
                <h2>FantaTech - Gen-AI</h2>
              </div>
              <nav className="mt-3">
                <ul>
                  <Link
                    className={`${menuOpen ? 'mobile-links' : 'links'} ${location.pathname === routes.scrape() ? 'active' : ''}`}
                    to={routes.scrape()}
                  >
                    <li>Scrape</li>
                  </Link>
                  <Link
                    className={`${menuOpen ? 'mobile-links' : 'links'} ${location.pathname === routes.crawl() ? 'active' : ''}`}
                    to={routes.crawl()}
                  >
                    <li>Crawl</li>
                  </Link>
                  <Link
                    className={`${menuOpen ? 'mobile-links' : 'links'} ${location.pathname === routes.pdfUpload() ? 'active' : ''}`}
                    to={routes.pdfUpload()}
                  >
                    <li>PDF Upload</li>
                  </Link>
                </ul>
              </nav>
            </aside>
    
            <main className="flex-1 min-w-0">{children}</main>
    
            {/* Overlay for mobile menu */}
            {/* {menuOpen && (
              <div
                className="fixed inset-0 z-30 bg-black bg-opacity-50 md:hidden"
                onClick={toggleMenu}
              ></div>
            )} */}
          </div>
        )
      }
    
      const rootElement = document.getElementById("app");
      client.createRoot(rootElement).render(<SideNavigationLayout><ScrapePage/></SideNavigationLayout>);
    </script>

    Without the fix, the <main> element would have min-width: min-content. This min-content would resolve using the longest unbreakable string in its content as part of its calculation. Thus, applying min-width: 0 overrides this behavior, thus allowing the child element to be narrower than its longest unbreakable string, thus allowing the horizontal overflow as desired.