skip to Main Content

The code in the following snippet renders a resonsive grid, that expands an element that is clicked.

const Demo = () => {

  const Item = ({content}) => {

    const [expanded, setExpanded] = React.useState(false);

    return (<div className = {
        expanded ? "expanded" : "item"
      }
      onClick = {
        () => setExpanded(!expanded)
      }>
        {content}
      </div>)
  }

  return (<div className = "grid" >
      <Item content = "Item 1" / >
      <Item content = "Item 2" / >
      <Item content = "Item 3" / >
      <Item content = "Item 4" / >
      <Item content = "Item 5" / >
      <Item content = "Item 6" / >
    </div>)
}

ReactDOM.render( < Demo / > , document.querySelector("#app"))
.grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
}

.item {
  display: flex;
  height: 100px;
  border: 1px solid black;
  justify-content: center;
  align-items: center;
}

.expanded {
  display: flex;
  height: 200px;
  border: 1px solid black;
  justify-content: center;
  align-items: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

<div id="app" />

When clicking on e.g. Item 2, the grid looks as follows:

Grid after clicking Item 2

However, in this case, I would like the grid to look like:

Expected grid after clicking Item 2

How would I go about fixing this? The solution does not have to use the a CSS Grid. However, the responsive width of the elements, and the responsive number of rows and columns must be maintained.

2

Answers


  1. I don’t think it’s really possible to do what do you want to do only with Grid property.

    Because we have two main grid size property: grid-template-rows and grid-template-columns.

    And the third one: grid-template-columns, you can make different sizes for rows and columns.

    But the main problem is if you get bigger than the column height, you will push everyone around.

    This is an example using the method I mentioned above:

    html, body {
        height: 100vh;
    }
    
    .grid {
        display: grid;
        grid-template-areas: "a b c";
        grid-template-areas: "a b c" "a b c";
        height: 100vh;
    }
    
    .item {
        background-color: blueviolet;
        align-items: center;
        text-align: center;
        height: 100px;
        width: 100px;
        border: solid;
    }
    
    .item:hover {
        height: 200px;
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <link rel="stylesheet" href="index.css">
    </head>
    <body>
        <div class="grid">
            <span class="item">1</span>
            <span class="item">2</span>
            <span class="item">3</span>
            <span class="item">4</span>
            <span class="item">5</span>
            <span class="item">6</span>
        </div>
    </body>
    </html>

    So to resolve your problem, use Flex property, you can do a grid with 3 columns and every column has its flex property.

    Like that:

    html, body {
        height: 100vh;
    }
    
    .grid {
        display: grid;
        grid-template-rows: auto;
        grid-template-columns: repeat(3, auto);
        height: 100vh;
    }
    
    .column-items {
        display: flex;
        flex-direction: column;
        background-color: blueviolet;
        align-items: center;
        text-align: center;
        height: fit-content;
        width: 100px;
    }
    
    .item {
        border: solid;
        height: 100px;
        width: 100px;
    }
    
    .item:hover {
        height: 200px;
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <link rel="stylesheet" href="index.css">
    </head>
    <body>
        <div class="grid">
            <div class="column-items">
                <span class="item">1</span>
                <span class="item">2</span>
            </div>
    
            <div class="column-items">
                <span class="item">3</span>
                <span class="item">4</span>
            </div>
    
            <div class="column-items">
                <span class="item">5</span>
                <span class="item">6</span>
            </div>
        </div>
    </body>
    </html>
    Login or Signup to reply.
  2. If you are looking for dense grid layout then on grid container you need mention that you need dense auto flow in rows:

    .grid {
      ...
      grid-auto-flow: row dense;
    }
    

    To properly increase the items’ height, increase row span as well:

    .expanded {
      height: 200px;
      grid-row: span 2;  /* <--- */
    }
    
    const Demo = () => {
        const Item = ({content}) => {
            const [expanded, setExpanded] = React.useState(false);
            return ( < div className = {            expanded ? "expanded" : "item" }
              onClick = { () => setExpanded(!expanded)
              } > { content} </div>) }
    
            return ( < div className = "grid" >
              <Item content = "Item 1" / >
              <Item content = "Item 2" / >
              <Item content = "Item 3" / >
              <Item content = "Item 4" / >
              <Item content = "Item 5" / >
              <Item content = "Item 6" / >
              </div>)
            }
            ReactDOM.render( < Demo / > , document.querySelector("#app"))
    .grid {
      display: grid;
      gap: 1rem;
      grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
    
      /* use dense layout */
      grid-auto-flow: row dense;
    }
    
    .item {
      display: flex;
      height: 100px;
      border: 1px solid black;
      justify-content: center;
      align-items: center;
    }
    
    .expanded {
      display: flex;
      border: 1px solid black;
      justify-content: center;
      align-items: center;
    
      height: calc(200px + 1rem);
      /* need to increase row span also */
      grid-row: span 2;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>
    
    <div id="app" />
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search