Building a UI from scratch, Responsive Sidebar and Header
Tags: react, javascript, tutorial, design
Published: 2019-07-29 10:53:47

---
title: Building a UI from scratch, Responsive Sidebar and Header
published: true
description: Turning it into a responsive design.
tags: react,javascript,tutorial,design
cover_image: https://i.postimg.cc/pLn7yLJ8/Screen-Shot-2019-07-24-at-23-02-39.png
series: Building a UI from scratch
---

This is the second article of the `Building a UI from scratch` series:
- Part #1: [Building a UI from scratch, based on a design with ReactJS](https://dev.to/llorentegerman/building-a-ui-from-scratch-based-on-a-design-with-reactjs-3l1e).
- Part #2: [Building a UI from scratch, Responsive Sidebar and Header](https://dev.to/llorentegerman/building-a-ui-from-scratch-responsive-sidebar-and-header-443g).
- Part #3: [Building a UI from scratch, Responsive Content](https://dev.to/llorentegerman/building-a-ui-from-scratch-responsive-content-6b9).

**Live demo**: [https://llorentegerman.github.io/react-admin-dashboard/](https://llorentegerman.github.io/react-admin-dashboard/)

**Repository**: [https://github.com/llorentegerman/react-admin-dashboard](https://github.com/llorentegerman/react-admin-dashboard)

## Responsive design
At the moment, our UI is not responsive, and we want it to look like this:
![](http://g.recordit.co/QzcP9sRsKH.gif)

As we don't have a responsive design to follow, we will keep it simple, only one breakpoint at **768px**. So any screen less than `768px` will be considered `mobile`.
The `Sidebar` will be isolated, on this component will be included: `Burger button`, `Desktop Sidebar` and `Mobile Sidebar`.
`SidebarComponent` for `Desktop` is already explained. In this article we will see how to convert it in a responsive sidebar.
In mobile screen (width <= 768px) `SidebarComponent` could have 2 different states: `collapsed` (default) or `expanded`.

### Collapsed:
In this state the whole sidebar will be hidden, then the `mainBlock` ([see App.js](https://github.com/llorentegerman/react-admin-dashboard/blob/v1-1-0/src/App.js)) will fill the whole width of the screen.
We need a button to `expand` the `Sidebar` and we will use a `BurgerIcon` for that (to copy the burger icon [click here](https://github.com/llorentegerman/react-admin-dashboard/blob/v1-1-0/src/assets/icon-burger.js)). That button will be in a absolute position, over the `header`:
![](https://i.postimg.cc/9Xg1mzv2/screenshotmobile1.png) 

### Expanded
In this state we will show the `Sidebar` and an `outsideLayer` that will fill the rest of the screen with a semitransparent background, and if you click it the `Sidebar` will be closed:
![](https://i.postimg.cc/sgQfVfDN/screenshotmobile3.png)


#### HeaderComponent.js
Since the `Burger button` will be over the `header` we need to add some `left-margin` to the `Header Title` to avoid this situation:
![](https://i.postimg.cc/D0NcBYq0/screenshotmobile2.png)

These are the most important parts of the new styles of `HeaderComponent.js`, as you can see I have included media queries to apply some special styles for mobile screens:
```
name: {
    ...,
    '@media (max-width: 768px)': {
        display: 'none' // <--- don't show the name on mobile
    }
},
separator: {
    ...,
    '@media (max-width: 768px)': {
        marginLeft: 12, // <--- less separation on mobile
        marginRight: 12
    }
},
title: {
    ...,
    '@media (max-width: 768px)': {
        marginLeft: 36 <--- to avoid overlapping with Burger button
    },
    '@media (max-width: 468px)': {
        fontSize: 20 <--- new fontSize for small devices. 
    }
}
```
I have also added a new style for the icons wrappers.

[View the changes: HeaderComponent.js](https://github.com/llorentegerman/react-admin-dashboard/compare/v1-0-0...v1-1-0#diff-9e795f3f52ccd33b20abf31c022ec55f)

[View full file: HeaderComponent.js](https://github.com/llorentegerman/react-admin-dashboard/blob/v1-1-0/src/components/header/HeaderComponent.js)


#### SidebarComponent.js
This component contains all the logic and it will change depending on these two variables:
- `expanded`: stored in the `state`
- `isMobile`: `true` when `window.innerWidth <= 768`

When the `Sidebar` is expanded, there are two differents ways to collapse it, clicking in some `MenuItem` or clicking on the `outsideLayer`. To manage this behaviour there are 2 methods:
```
onItemClicked = (item) => {
    this.setState({ expanded: false });
    return this.props.onChange(item);
}

toggleMenu = () => this.setState(prevState => ({ expanded: !prevState.expanded }));
```
`toggleMenu` will be fired when you click on the `Burger button` (if sidebar is collapsed) or when you click on the `outsideLayer` (if sidebar is expanded).

Here is the new version of `SidebarComponent`:
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=SidebarComponent_v1-1-0.js %}


and here is the `renderBurger` method:
```
renderBurger = () => {
    return <div onClick={this.toggleMenu} className={css(styles.burgerIcon)}>
        <IconBurger />
    </div>
}
```

We are wrapping the component inside a `div` with `position: relative`, and that is to allow to the `Sidebar` fill all the screen, otherwise it will looks like this:

![](http://g.recordit.co/cxsvbwxmEE.gif)

As you can see, we are using the `breakpoints` property of [simple-flexbox](https://www.npmjs.com/package/simple-flexbox), for example:
```
<Row
    className={css(styles.mainContainer)}
    breakpoints={{ 768: css(styles.mainContainerMobile) }}
>
```
it means that if `window.innerWidth <= 768` `mainContainerMobile` styles will be applied.

Reading the follow part of the code, you will se that if we are on `mobile` screen, and `expanded = false`, just the `Burger button` will be rendered, and if `expanded = true` the `Sidebar` and `outsideLayer` will be shown.
```
{(isMobile && !expanded) && this.renderBurger()}
<Column className={css(styles.container)}
    breakpoints={{ 768: css(styles.containerMobile, expanded ? styles.show : styles.hide) }}>
    ...
</Column>
{isMobile && expanded &&
    <div className={css(styles.outsideLayer)} onClick={this.toggleMenu}></div>}
```

These are the new styles applied to `SidebarComponent.js`, check that on `mobile` the position of the `container` will be `absolute` to `overlay` the `mainBlock` and fill the whole screen. When `expanded = false` it will be shifted to the left, out of the screen (`left: -255px`), and when `expanded = true` it will be shown, shifted to the original position (`left: 0px`). You can also see the `transition` property to make a smooth display of the element. `outsideLayer` will fill the entire screen but will be placed behind the `Sidebar` (see `zIndex`):

```
burgerIcon: {
    cursor: 'pointer',
    position: 'absolute',
    left: 24,
    top: 34
},
container: {
    backgroundColor: '#363740',
    width: 255,
    paddingTop: 32,
    height: 'calc(100% - 32px)'
},
containerMobile: {
    transition: 'left 0.5s, right 0.5s',
    position: 'absolute',
    width: 255,
    height: 'calc(100% - 32px)',
    zIndex: 901
},
mainContainer: {
    height: '100%',
    minHeight: '100vh'
},
mainContainerMobile: {
    position: 'absolute',
    width: '100vw',
    minWidth: '100%',
    top: 0,
    left: 0
},
outsideLayer: {
    position: 'absolute',
    width: '100vw',
    minWidth: '100%',
    height: '100%',
    backgroundColor: 'rgba(0,0,0,.50)',
    zIndex: 900
},
hide: {
    left: -255
},
show: {
    left: 0
}
```

[View the changes: SidebarComponent.js](https://github.com/llorentegerman/react-admin-dashboard/compare/v1-0-0...v1-1-0#diff-c83e6c47084049d5b258f003efdd1b8e)

[View full file: SidebarComponent.js](https://github.com/llorentegerman/react-admin-dashboard/blob/v1-1-0/src/components/sidebar/SidebarComponent.js)


#### App.js
I have changed the `container` styles so that it fills all the full height of the screen:
```
container: {
    height: '100%',
    minHeight: '100vh'
}
```

and I've included an event to re-render the full application at each `resize`:
```
componentDidMount() {
    window.addEventListener('resize', this.resize);
}

componentWillUnmount() {
    window.removeEventListener('resize', this.resize);
}

resize = () => this.forceUpdate();
```

[View the changes: App.js](https://github.com/llorentegerman/react-admin-dashboard/compare/v1-0-0...v1-1-0#diff-14b1e33d5bf5649597cdc0e4f684dadd)

[View full file: App.js](https://github.com/llorentegerman/react-admin-dashboard/blob/v1-1-0/src/App.js)

New articles from this series are coming.

Thanks for reading