Compound Components and Layout Components in React
Tags: react, javascript, composition, webdev
Published: 2022-03-04 16:28:22

Hello!

Writing resilient components with flexible composition is a bit tricky in React. In this post we will see the difference, how and when to use `layout` and `compound` components. Let's get started.

## Layout Components

These component are used for creating reusable layouts in a react app. They accept UI trees as props and then position them as required visually. The props are basically used to fill up holes in the layout component UI, it's upto this component to position them in correct places.

One important thing to note is that `Layout Components` don't usually need their own state but there could be use cases depending on the situation (mostly state related to UI rather than external data).

When we start building a website from scratch it's always a good idea to visualize the UI in respect of the different parts that can be abstracted into it's own component. As an example below is the homepage of this website.
![Dev.to Homepage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h82nbstnq0gvw6ia5aed.PNG)

As we can see, the website can be divided into 3 main parts, the `Left Sidebar`, `Main View` and the `Right Sidebar`. So normally using composition we will write it as,

```jsx
function App() {
  return (
    <div>
      <Home
        leftSidebar={
          <LeftSidebar>
            <Community />
            <Other />
          </LeftSidebar>
        }
        mainView={
          <MainView>
            <Header />
            <Feed />
          </MainView>
        }
        rightSidebar={
          <RightSidebar>
            <Listings />
            <News />
          </RightSidebar>
        }
      />
    </div>
  )
}

function LeftSidebar({ children }) {
  return <div>{children}</div>
}

function MainView({ children }) {
  return <div>{children}</div>
}

function RightSidebar({ children }) {
  return <div>{children}</div>
}

function Home({ leftSidebar, mainView, rightSidebar }) {
  return (
    <div>
      {leftSidebar}
      {mainView}
      {rightSidebar}
    </div>
  )
}
```

We can apply different styling to each of these abstracted components and position them as and when required in Home Component, each prop here fills a hole in the UI.

## Compound Components

These components also use composition model, the simplest overview of these types components can be found in the `<select>`/`<option>` tag in html. These tags have a implicit state that enables it to show the currently selected option while still giving the developer full access to the rendering logic for each of the pieces. 
For example if we want to disable one of the options in the UI we can easily do it

```js
  <select value={value}>
    {options.map(option => (
       <option value={option} disabled={option === disableValue} />
    )}
  </select>
```

We can create components based on this concept, such existing UI Libraries or from scratch, we will be using Menu Component and it's `option` equivalent MenuItem provided by MUI.
 
{% codesandbox bqzm7b %}

Here, in ListMenu Component, we are managing the state as well as using MUI components in a coherent way.

```js
   <Menu
      anchorEl={anchorEl}
      open={open}
      onClose={handleClose}
    >
     {options.map((option, index) => (
       <MenuItem
         key={option}
         disabled={index === 0}
         selected={index === selectedIndex}
         onClick={(event) => handleMenuItemClick(event, index)}
       >
         {option}
       </MenuItem>
     ))}
   </Menu>
```

We can change the styles based on the requirements, disable some options (first option is disabled) and much more, add images along with text? sure, we can customize as much as we want. 

Other developers can use this abstraction without worrying about handling state, they can customize styles by passing className to the component as a prop. And that's Compound Components!

I loved writing this post. If you have any questions or suggestions, feel free to reach out to me!

Connect with me on [Twitter](https://twitter.com/ImPrinceRajRoy), [Github](https://github.com/PrinceRajRoy)