Search code examples
reactjscss-gridstyled-componentssplit-screen

unable to properly render a react split-screen component using grid and styled-components


I just learned how to create a split-screen (2 screens) component that uses "display: flex" on the parent-container and "flex: 1" on its children to produce a left-component and a right-component. Now I'm trying to create a split-screen (5 screens) component that uses "display: grid" to produce 3 columns and two rows with a left sidebar that takes up the first column and both rows and the four other screens each take up 1 column & 1 row (a top-left screen, a top-right screen, a bottom-left screen and a bottom-right screen). I'm able to display the grid with the code I have so far but I can only get the first row, first column to display any text (image below). I'm using React Router and styled-components which shouldn't be part of the problem but maybe it will help provide you with some context. There are three files: App.js (the starting point of my app's code & imports Home.js), Home.js (imports Splitscreen.js) and SplitScreen.js (contains the problematic component). I realize that I could have achieved the desired result with flexbox but I thought I would have more control using Grid. Any help would be greatly appreciated.

the screenshot of the grid created by my code: screenshot of the grid that shows up in the dev tools inspector

App.js code below:
import React from "react";
import { Routes, Route } from "react-router-dom";
import styled, { createGlobalStyle } from "styled-components";
import {NoMatch} from "./pages/NoMatch";
import {Dashboard} from "./pages/Dashboard";
import {About} from "./pages/About";
import {Home} from "./pages/Home";
import { LayoutNavigation } from "./components/LayoutNavigation";


export default function App() {
  return (
    <>
      <Routes>
        <Route path="/" element={<LayoutNavigation />}>
          <Route index element={<Home />} />
          <Route path="about" element={<About />} />
          <Route path="dashboard" element={<Dashboard />} />
          <Route path="*" element={<NoMatch />} />
        </Route>
      </Routes>
    </>
  );
}
Home.js code below
import { SplitScreenQuad } from "../components/SplitScreen";
import styled from "styled-components";

const Sidebar = () => {
  return (
    <div>
      <h1 style={{ backgroundColor: "lightblue" }}>Sidebar</h1>
    </div>
  );
};

const UserInputFields = () => {
  <div>
    <h1 style={{ backgroundColor: "lightgreen" }}>UserInputFields</h1>;
  </div>;
};

const UserData = () => {
  <div>
    <h1 style={{ backgroundColor: "lightgreen" }}>UserData</h1>;
  </div>;
};

const TableResults = () => {
  <div>
    <h1 style={{ backgroundColor: "pink" }}>TableResults</h1>;
  </div>;
};

const ImageResults = () => {
  <div>
    <h1 style={{ backgroundColor: "yellow" }}>ImageResults</h1>;
  </div>;
};

export const Home = () => {
  return (
    <>
      <h1>HOME</h1>
      <SplitScreenQuad
        sidebar={Sidebar}
        topleft={UserInputFields}
        topright={UserData}
        bottomleft={TableResults}
        bottomright={ImageResults}
      />
    </>
  );
};

/*Filename: SplitScreen.js*/
import React from "react";
import styled from "styled-components";

export const SplitScreenQuad = ({
  sidebar: Sidebar,
  topleft: Topleft,
  topright: Topright,
  bottomleft: Bottomleft,
  bottomright: Bottomright,
}) => {
  return (
    <>
      <ContainerQuad>
        <PaneQuad>
          <Sidebar id="sidebar" />
        </PaneQuad>
        <PaneQuad>
          <Topleft id="topleft" />
        </PaneQuad>
        <PaneQuad>
          <Topright id="topright" />
        </PaneQuad>
        <PaneQuad>
          <Bottomleft id="bottomleft" />
        </PaneQuad>
        <PaneQuad>
          <Bottomright id="bottomright" />
        </PaneQuad>
      </ContainerQuad>
    </>
  );
};

const ContainerQuad = styled.div`
  display: grid;
  grid-template-columns: auto 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 1rem;
  background-color: lightcoral;
  #sidebar {
    grid-column: 1;
    grid-row: 1 / span 2;
  }
  #topleft {
    grid-column: 2;
    grid-row: 1;
  }
  #topright {
    grid-column: 3;
    grid-row: 1;
  }
  #bottomleft {
    grid-column: 2;
    grid-row: 2;
  }
  #bottomright {
    grid-column: 3;
    grid-row: 2;
  }
`;

const PaneQuad = styled.div``;

Solution

  • You're missing the return in several of your components. Additionally, you're trying to set css properties using ids that aren't being passed to the proper element.

    // make sure you're returning something in these components:
    
    const Sidebar = () => (
      <div>
        <h1 style={{ backgroundColor: "lightblue" }}>Sidebar</h1>
      </div>
    );
    
    const UserInputFields = () => (
      <div>
        <h1 style={{ backgroundColor: "lightgreen" }}>UserInputFields</h1>;
      </div>
    );
    
    const UserData = () => (
      <div>
        <h1 style={{ backgroundColor: "lightgreen" }}>UserData</h1>;
      </div>
    );
    
    const TableResults = () => (
      <div>
        <h1 style={{ backgroundColor: "pink" }}>TableResults</h1>;
      </div>
    );
    
    const ImageResults = () => (
      <div>
        <h1 style={{ backgroundColor: "yellow" }}>ImageResults</h1>;
      </div>
    );
    
    

    As for the placement of the elements in the grid, no ids are needed. Just create a wrapper for the sidebar that sets its grid-row: 1 / span 2. That's all that is needed. You don't need to specifically set the other elements in the grid. The remaining ones will auto-flow into the quad portion of the grid.

    
    const SplitScreenQuad = ({
      sidebar: Sidebar,
      topleft: Topleft,
      topright: Topright,
      bottomleft: Bottomleft,
      bottomright: Bottomright
    }) => {
      return (
        <>
          <ContainerQuad>
            <SidebarPane>
              <Sidebar />
            </SidebarPane>
            <PaneQuad>
              <Topleft />
            </PaneQuad>
            <PaneQuad>
              <Topright />
            </PaneQuad>
            <PaneQuad>
              <Bottomleft />
            </PaneQuad>
            <PaneQuad>
              <Bottomright />
            </PaneQuad>
          </ContainerQuad>
        </>
      );
    };
    
    // You can simplify here
    const ContainerQuad = styled.div`
      display: grid;
      grid-template-columns: auto 1fr 1fr;
      grid-template-rows: 1fr 1fr;
      gap: 1rem;
      background-color: lightcoral;
    `;
    
    
    // Only the Sidebar needs special treatment:
    const SidebarPane = styled.div`
      grid-row: 1 / span 2;
    `;
    
    const PaneQuad = styled.div``;