Building a UI from scratch, Responsive Content
Tags: react, javascript, tutorial, design
Published: 2019-08-05 20:19:31

---
title: Building a UI from scratch, Responsive Content
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 third 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 Content
As part of the 3rd article, we will see how to make the content that appears in the design ([see Part #1](https://dev.to/llorentegerman/building-a-ui-from-scratch-based-on-a-design-with-reactjs-3l1e)).
We want to make it responsive, and we want it to look like this:
![](http://g.recordit.co/cWkPDhuw0P.gif)

As I said in the previous article, we don't have a responsive design to follow, so we will keep it simple, a main breakpoint at **768px**.
We can identify 3 main sections in the content:
```
1- Row of MiniCards
2- Today's trends (graph + stats)
3- Row with 2 cards:
    4- Unresolved tickets
    5- Tasks
```

![](https://i.postimg.cc/9fTPpZLv/content1.png)

#### MiniCardComponent.js
This is a simple Component, just a Column with a `title` and `value`. The content of the column has to be centered.

{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=MiniCardComponent_v1-2-0.js %}

styles:
```javascript
container: {
    backgroundColor: '#FFFFFF',
    border: '1px solid #DFE0EB',
    borderRadius: 4,
    cursor: 'pointer',
    height: 70,
    maxWidth: 350,
    marginRight: 30,
    padding: '24px 32px 24px 32px',
    ':hover': {
        borderColor: '#3751FF',
        ':nth-child(n) > span': {
            color: '#3751FF'
        }
    }
},
title: {
    color: '#9FA2B4',
    fontFamily: 'Muli',
    fontStyle: 'normal',
    fontWeight: 'bold',
    fontSize: 19,
    lineHeight: '24px',
    letterSpacing: '0.4px',
    marginBottom: 12,
    minWidth: 102,
    textAlign: 'center'
},
value: {
    color: '#252733',
    fontFamily: 'Muli',
    fontStyle: 'normal',
    fontWeight: 'bold',
    fontSize: 40,
    letterSpacing: '1px',
    lineHeight: '50px',
    textAlign: 'center'
}
```

Pay attention to the `container` styles, on `:hover` we want to change the `borderColor` and `fontColor` of `title` and `value`, but, by default `aphrodite` sets the styles as `!important` so, we cannot change the styles of the children (`title`, `value`) from their parent (`container`). To be able to do that we have to import `aphrodite` in a differnet way than we normally do.
```
import { StyleSheet, css } from 'aphrodite/no-important';
```
Now we can overwrite the styles of the `children` from their `parents`.

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


#### TodayTrendsComponent.js
This component is a `Row` with the following structure:
```
1- Column
    3- Row ({ horizontal: space-between })
        5- Column with title and subtitle
        6- legend
    4- Chart
2- Column: list of stats
```

![](https://i.postimg.cc/qqFndxQB/todaystrends.png)

It can be defined as follows:
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=TodayTrendsComponent_v1-2-0.js %}

where `renderLegend` and `renderStat` are defined as follows:

{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=TodayTrendsComponent2_v1-2-0.js %}

for the `chart` I have used `react-svg-line-chart`, to install it, just type:
```javascript
yarn add react-svg-line-chart
```

and these are the styles:
```javascript
container: {
    backgroundColor: '#FFFFFF',
    border: '1px solid #DFE0EB',
    borderRadius: 4,
    cursor: 'pointer'
},
graphContainer: {
    marginTop: 24,
    marginLeft: 0,
    marginRight: 0,
    width: '100%'
},
graphSection: {
    padding: 24
},
graphSubtitle: {
    fontFamily: 'Muli',
    fontStyle: 'normal',
    fontWeight: 'normal',
    fontSize: 12,
    lineHeight: '16px',
    letterSpacing: '0.1px',
    color: '#9FA2B4',
    marginTop: 4,
    marginRight: 8
},
graphTitle: {
    fontFamily: 'Muli',
    fontStyle: 'normal',
    fontWeight: 'bold',
    fontSize: 19,
    lineHeight: '24px',
    letterSpacing: '0.4px',
    color: '#252733'
},
legendTitle: {
    fontFamily: 'Muli',
    fontStyle: 'normal',
    fontWeight: '600',
    fontSize: 12,
    lineHeight: '15px',
    letterSpacing: '0.1px',
    color: '#9FA2B4',
    marginLeft: 8
},
separator: {
    backgroundColor: '#DFE0EB',
    width: 1,
    minWidth: 1,
},
statContainer: {
    borderBottom: '1px solid #DFE0EB',
    padding: '24px 32px 24px 32px',
    height: 'calc(114px - 48px)',
    ':last-child': {
        border: 'none'
    }
},
stats: {
    borderTop: '1px solid #DFE0EB',
    width: '100%'
},
statTitle: {
    fontFamily: 'Muli',
    fontStyle: 'normal',
    fontWeight: '600',
    fontSize: 16,
    lineHeight: '22px',
    letterSpacing: '0.3px',
    textAlign: 'center',
    color: '#9FA2B4',
    whiteSpace: 'nowrap',
    marginBottom: 6
},
statValue: {
    fontFamily: 'Muli',
    fontStyle: 'normal',
    fontWeight: 'bold',
    fontSize: 24,
    lineHeight: '30px',
    letterSpacing: '0.3px',
    textAlign: 'center',
    color: '#252733'
}
```

Notice that `container` will become a `column` when `window.innerWidth <= 1024`, so the `stats` column will be stacked under the `graph`. At same size the `separator` will disappear, and `graph` and `stats` will fill the whole width.
Pay attention to `statContainer` style, where we are setting borders for every `child` except for the last.

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


#### CardComponent.js
As I said before, the 3rd section of the `content` page is a `Row` with 2 component. These components have many similar characteristics, so we can abstract the design like this:

```
1- Container (column)
    2- Row: 
        3- Column: title and subtitle (received by props)
        4- Link (view details or view all)
    5- List of items (received by props)
```

Code:
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=CardComponent_v1-2-0.js %}

`renderItem`:
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=CardComponent2_v1-2-0.js %}

styles:
```javascript
container: {
        backgroundColor: '#FFFFFF',
        border: '1px solid #DFE0EB',
        borderRadius: 4,
        padding: '24px 32px 12px 32px'
    },
    containerMobile: {
        padding: '12px 16px 6px 16px !important'
    },
    itemContainer: {
        marginLeft: -32,
        marginRight: -32,
        paddingLeft: 32,
        paddingRight: 32,
        paddingBottom: 18,
        paddingTop: 18,
        maxHeight: 22,
        borderBottom: '1px solid #DFE0EB',
        ':last-child': {
            borderBottom: 'none'
        }
    },
    itemContainerMobile: {
        marginLeft: -16,
        marginRight: -16,
        paddingLeft: 16,
        paddingRight: 16
    },
    link: {
        fontFamily: 'Muli',
        fontStyle: 'normal',
        fontWeight: '600',
        fontSize: 14,
        lineHeight: '20px',
        letterSpacing: '0.2px',
        color: '#3751FF',
        textAlign: 'right',
        cursor: 'pointer'
    },
    subtitle: {
        fontFamily: 'Muli',
        fontStyle: 'normal',
        fontWeight: 'normal',
        fontSize: 12,
        lineHeight: '16px',
        letterSpacing: '0.1px',
        color: '#9FA2B4'
    },
    subtitle2: {
        color: '#252733',
        marginLeft: 2
    },
    title: {
        fontFamily: 'Muli',
        fontStyle: 'normal',
        fontWeight: 'bold',
        fontSize: 19,
        lineHeight: '24px',
        letterSpacing: '0.4px',
        color: '#252733'
    }
```

See in `itemContainer` that all items will have `border` except the last one.

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


#### UnresolvedTicketsComponent.js
This component will be done based on `CardComponent`, it will look like this:
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=UnresolvedTicketsComponent_v1-2-0.js %}

where `renderStat` is:
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=UnresolvedTicketsComponent2_v1-2-0.js %}

We need styles only for the `title` and `value`, all the others are set in `CardComponent`:
```javascript
itemTitle: {
    fontFamily: 'Muli',
    fontStyle: 'normal',
    fontWeight: '600',
    fontSize: 14,
    lineHeight: '20px',
    letterSpacing: '0.2px',
    color: '#252733'
},
itemValue: {
    color: '#9FA2B4'
}
```

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


#### TasksComponent.js
As `UnresolvedTicketsComponent`, this component will be done based on `CardComponent`, it will look like this:
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=TasksComponent_v1-2-0.js %}

As you can see, the first item looks different from the others, it has a `gray title` and the `add button`. The rest of the items are stored in the state:
```javascript
state = { items: [
    {title: 'Finish ticket update', checked: false, tag: TAGS.URGENT },
    {title: 'Create new ticket example', checked: false, tag: TAGS.NEW },
    {title: 'Update ticket report', checked: true, tag: TAGS.DEFAULT }
]};
```

These are the possible TAGS:

```javascript
const TAGS = {
    URGENT: { text: 'URGENT', backgroundColor: '#FEC400', color: '#FFFFFF' },
    NEW: { text: 'NEW', backgroundColor: '#29CC97', color: '#FFFFFF' },
    DEFAULT: { text: 'DEFAULT', backgroundColor: '#F0F1F7', color: '#9FA2B4' },
}
```

and this is the `renderTask` function that will use other 2 functions: `renderTag` and `renderCheckbox`:
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=TasksComponent2_v1-2-0.js %}

For the `checkbox` we are using two new icons that you can copy from here: [checkbox-on](https://github.com/llorentegerman/react-admin-dashboard/tree/v1-2-0/src/assets/checkbox-on.js) and [checkbox-off](https://github.com/llorentegerman/react-admin-dashboard/tree/v1-2-0/src/assets/checkbox-off.js),

These are the styles:
```javascript
addButton: {
    backgroundColor: '#F0F1F7',
    color: '#9FA2B4',
    fontSize: 20,
    padding: 7
},
itemTitle: {
    color: '#252733',
    fontFamily: 'Muli',
    fontStyle: 'normal',
    fontWeight: '600',
    fontSize: 14,
    letterSpacing: '0.2px',
    lineHeight: '20px'
},
itemValue: {
    color: '#9FA2B4'
},
greyTitle: {
    color: '#C5C7CD'
},
tagStyles: {
    borderRadius: 5,
    cursor: 'pointer',
    fontFamily: 'Muli',
    fontStyle: 'normal',
    fontWeight: 'bold',
    fontSize: 11,
    letterSpacing: '0.5px',
    lineHeight: '14px',
    padding: '5px 12px 5px 12px'
},
checkboxWrapper: {
    cursor: 'pointer',
    marginRight: 16
}
```

You can see in the repository code that I added some events to do this component interactive.

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

#### ContentComponent.js
Now we have to combine these components into one. As I said before is a `Column` with 3 sections:
```
1- Row of MiniCardComponent
2- TodayTrendsComponent
3- Row with 2 components:
    4- UnresolvedTicketsComponent
    5- TasksComponent
```

The first section is probably the most complex, because we have to combine some styles. We have 4 `cards`, and we always want the same number of cards in each row regardless of the width of the screen. That is:
- 4 cards in a row, or
- 2 cards in each row, in two different rows, or
- 1 card in each row, in four different rows
![](http://g.recordit.co/5zjnfmBsgN.gif)

but we don't want something like this:
![](http://g.recordit.co/Lf6xgHPzEO.gif)

I think it's a good idea if we group them into pairs in this way:
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=ContentComponent_v1-2-0.js %}

so, when the main `row` is wider than the container, it will be divided into two new `rows`, and so on.

For `TodayTrendsComponent` is easy, we just need to wrap it in a `div` to apply some margins.

{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=ContentComponent2_v1-2-0.js %}

and the last section is a `row` with `UnresolvedTicketsComponent` and `TasksComponent` that will become a `column` when `window.innerWidth <= 1024`,
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=ContentComponent3_v1-2-0.js %}

here is the full code:
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=ContentComponent4_v1-2-0.js %}

styles:
```javascript
cardsContainer: {
    marginRight: -30,
    marginTop: -30
},
cardRow: {
    marginTop: 30,
    '@media (max-width: 768px)': {
        marginTop: 0
    }
},
miniCardContainer: {
    flexGrow: 1,
    marginRight: 30,
    '@media (max-width: 768px)': {
        marginTop: 30,
        maxWidth: 'none'
    }
},
todayTrends: {
    marginTop: 30
},
lastRow: {
    marginTop: 30
},
unresolvedTickets: {
    marginRight: 30,
    '@media (max-width: 1024px)': {
        marginRight: 0
    }
},
tasks: {
    marginTop: 0,
    '@media (max-width: 1024px)': {
        marginTop: 30,
    }
}
```

pay attention to the negative margins of `cardsContainer` as they will absorb the excess margins of the elements that are located on the edges, to avoid this kind of things:
![](https://i.postimg.cc/VNmVvp3V/content2.png)

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


#### MainComponent (App.js)
To finish we have to include the `ContentComponent` in our `MainComponent`
{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=App_v1-2-0.js %}

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

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

#### SidebarComponent.js (important fix)
We have to include a change to our `Sidebar`, because at the moment, a transparent layer is filling all the screen on mobile so we cannot click any element.
We are applying these styles to the `mainContainerMobile`:
```javascript
 mainContainerMobile: {
    ...
    width: '100%',
    minWidth: '100vh',
}
```
but we want those styles only when the `Sidebar` is `expanded`, so we will apply these changes to our component:

{% gist https://gist.github.com/llorentegerman/b0c7eb1df6342f742372f01f4092c3d6 file=SidebarComponent_v1-2-0.js %}

styles:
```javascript
...
mainContainerMobile: {
    position: 'absolute',
    top: 0,
    left: 0
},
mainContainerExpanded: {
    width: '100%',
    minWidth: '100vh',
}
...
```

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

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


### Conclusion
This is the last article in the series, the goal was to show how to build a UI from scratch based on a design and how to turn it into a responsive UI. We have mainly used [aphrodite (^ 2.3.1)](https://www.npmjs.com/package/aphrodite) for the styles and [simple-flexbox (^ 2.2.1)](https://www.npmjs.com/package/simple-flexbox) to make the layout.

I hope it was useful.

You can star the [repo](https://github.com/llorentegerman/react-admin-dashboard) and follow me on [GitHub](https://github.com/llorentegerman) to see other examples that I will add.

Thanks for reading.