Search code examples
csssasslayoutcss-gridgrid-layout

Dynamic modification of grid-template-rows


I have a React component with this structure the tools and searchPanel blocks have fixed heights. the main block should occupy the remaining space:


    <div className={`reference-container`}> 
        {
         isToolsVisible && <div className={`tools`}></div>
        }
        {
         isSeracpPanleVisible && <div className={`searchPanel`}></div>
        }
        <div className={`mainContent`}></div>
    </div>

I have a stylesheet file:

.reference-container {
    $toolHeight: 100px;
    $serachPanelHeight: 50px;
    
    height: 100%;
    display: grid;
    grid-template-areas: 
      "tools"
      "serachPanel"
      "mainContent";
    grid-template-rows: $toolHeight $serachPanelHeight 1fr;
    
    .tools {
        grid-area: tools
    }
    .searchPanel {
        grid-area: searchPanel
    }
    .mainContent {
        grid-area: mainContent
    }
} 

Depending on the condition, and are displayed. However, I'm not sure how to correctly change grid-template-areas when the conditional blocks are absent.

I tried to set several conditional modifier classes for the parent container, and based on them, dynamically define the grid-template in the CSS file.

html(JSX)

<div className={`reference-container ${isToolsVisible ? 'with-tools' : ''} ${isSearchPanelVisible ? 'with-search-panel' : ''}`}>
  {isToolsVisible && <div className={`tools`}></div>}
  {isSearchPanelVisible && <div className={`searchPanel`}></div>}
  <div className={`mainContent`}></div>
</div>

SCSS

.reference-container {
  $toolHeight: 100px;
  $searchPanelHeight: 50px;

  height: 100%;
  display: grid;
  grid-template-rows: 1fr;
  
  &.with-tools {
    grid-template-areas: 
      "tools"
      "mainContent";
    grid-template-rows: $toolHeight 1fr;
  }
  
  &.with-search-panel {
    grid-template-areas: 
      "searchPanel"
      "mainContent";
    grid-template-rows: $searchPanelHeight 1fr;
  }
  
  .tools {
    grid-area: tools;
  }
  
  .searchPanel {
    grid-area: searchPanel;
  }
  
  .mainContent {
    grid-area: mainContent;
  }
}

I think this is not the correct solution, maybe it's better not to use grid at all in this case?please advise a better one. Thank u advance!


Solution

  • You are doing it too complicated.

    The elements in the HTML are in the same order that you want them to be seen, you can let the grid-flow take care of this. You only need to set the main content to the last row:

    .container {
        display: grid;
        height: 300px;
        border: solid 1px black;
        grid-template-rows: auto auto 1fr;
        margin: 5px;
    }
    
    .tools {
        height: 100px;
        background-color: lightblue;
    }
    
    .search {
        height: 50px;
        background-color: lightgreen;
    }
    
    .main {
      background-color: yellow;
      grid-row: -2 / -1;
    }
    <div class="container">
    <div class="tools"></div>
    <div class="search"></div>
    <div class="main"></div>
    </div>
    <div class="container">
    <div class="search"></div>
    <div class="main"></div>
    </div>
    <div class="container">
    <div class="tools"></div>
    <div class="main"></div>
    </div>
    <div class="container">
    <div class="main"></div>
    </div>