CSS charts: How to create an organizational chart

In previous tutorials we’ve learned how to create different types of charts including bar charts, thermometer charts, and donut charts. Today we’ll continue this journey by building a CSS-only organizational chart.

Ready to test your CSS skills?

The organizational chart we’re building

Here’s the CSS chart we’ll be creating:

It consists of four levels and describes the hierarchical structure of a company.

What is an organizational chart?

To find out what is an organizational chart, let’s borrow Wikipedia’s definition:

“An organizational chart , also called organigram or organogram, is a diagram that shows the structure of an organization and the relationships and relative ranks of its parts and positions/jobs. The term is also used for similar diagrams, for example ones showing the different elements of a field of knowledge or a group of languages.”

Here’s an example:

By S.s.kulkarni9090 – Own work, CC BY-SA 3.0

This type of chart is commonly used for presenting the relationships between the people or departments of a company. On a corporate website, you will probably find it on the “About Us” or “Company” page.

You’ll also see organizational charts used for family trees (check out the British Royal Family tree and line of succession on the BBC’s website). They’re ideally suited for illustrating hierarchy.

1. Specify the container

Our chart in CSS will live inside a container:

1
<div class="container">
2
  <!-- Chart goes here -->
3
</div>

2. Define some basic styles

Before going through its levels, we’ll set up a few reset rules and helper classes:

1
:root {
2
  --level-1: #8dccad;
3
  --level-2: #f5cc7f;
4
  --level-3: #7b9fe0;
5
  --level-4: #f27c8d;
6
  --black: black;
7
}
8

9
* {
10
  padding: 0;
11
  margin: 0;
12
  box-sizing: border-box;
13
}
14

15
ol {
16
  list-style: none;
17
}
18

19
body {
20
  margin: 50px 0 100px;
21
  text-align: center;
22
  font-family: "Inter", sans-serif;
23
}
24

25
.container {
26
  max-width: 1000px;
27
  padding: 0 10px;
28
  margin: 0 auto;
29
}
30

31
.rectangle {
32
  position: relative;
33
  padding: 20px;
34
  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
35
}

Notice the rectangle class. We’ll append this to every node/element of our chart.

Note: for simplicity, I haven’t optimized the CSS. This will help you get a better understanding of the styles of each level. 

3. Specify the levels in your CSS chart

At this point, we’re ready to specify the chart levels; as we discussed earlier, here we’ll have four of them:

LevelsLevelsLevels

Each level will represent a role in a company starting from the highest-ranking one. Keep this in mind as you’re generating a hierarchy chart design.

Level #1

The first level will only include a single node:

Level 1Level 1Level 1

HTML

To describe it, we’ll use an h1 tag as it’s the most important part of our chart:

1
<h1 class="level-1 rectangle">...</h1>

CSS

We’ll use its ::before pseudo-element to create a relationship between the first and second levels:

1
/*CUSTOM VARIABLES HERE*/
2

3
.level-1 {
4
  width: 50%;
5
  margin: 0 auto 40px;
6
  background: var(--level-1);
7
}
8

9
.level-1::before {
10
  content: "";
11
  position: absolute;
12
  top: 100%;
13
  left: 50%;
14
  transform: translateX(-50%);
15
  width: 2px;
16
  height: 20px;
17
  background: var(--black);
18
}

Level #2

The second level will consist of two nodes:

Level 2Level 2Level 2

As we’ll see in a moment, each node will include other child nodes.

These child nodes will represent lower levels of the managerial hierarchy.

HTML

To describe it, we’ll use an ordered list with two list items. Each list item will contain an h2 element:

1
<ol class="level-2-wrapper">
2
  <li>
3
    <h2 class="level-2 rectangle">...</h2>
4
  </li>
5
  <li>
6
    <h2 class="level-2 rectangle">...</h2>
7
  </li>
8
</ol>

CSS

Thanks to CSS Grid, we’ll create the layout for this level.

Next, we’ll use the ::before pseudo-element of specific elements for creating the associations between the nodes of this level and the adjacent levels:

1
/*CUSTOM VARIABLES HERE*/
2

3
.level-2-wrapper {
4
  position: relative;
5
  display: grid;
6
  grid-template-columns: repeat(2, 1fr);
7
}
8

9
.level-2-wrapper::before {
10
  content: "";
11
  position: absolute;
12
  top: -20px;
13
  left: 25%;
14
  width: 50%;
15
  height: 2px;
16
  background: var(--black);
17
}
18

19
.level-2-wrapper::after {
20
  display: none;
21
  content: "";
22
  position: absolute;
23
  left: -20px;
24
  bottom: -20px;
25
  width: calc(100% + 20px);
26
  height: 2px;
27
  background: var(--black);
28
}
29

30
.level-2-wrapper li {
31
  position: relative;
32
}
33

34
.level-2-wrapper > li::before {
35
  content: "";
36
  position: absolute;
37
  bottom: 100%;
38
  left: 50%;
39
  transform: translateX(-50%);
40
  width: 2px;
41
  height: 20px;
42
  background: var(--black);
43
}
44

45
.level-2 {
46
  width: 70%;
47
  margin: 0 auto 40px;
48
  background: var(--level-2);
49
}
50

51
.level-2::before {
52
  content: "";
53
  position: absolute;
54
  top: 100%;
55
  left: 50%;
56
  transform: translateX(-50%);
57
  width: 2px;
58
  height: 20px;
59
  background: var(--black);
60
}
61

62
.level-2::after {
63
  display: none;
64
  content: "";
65
  position: absolute;
66
  top: 50%;
67
  left: 0%;
68
  transform: translate(-100%, -50%);
69
  width: 20px;
70
  height: 2px;
71
  background: var(--black);
72
}

Notice that we also define the ::after pseudo-element of the second-level nodes. This will appear only on small screens.

Level #3

The third level will include four nodes.

We’ll associate the first two nodes with the first node of the second level, while the last two with its second node: 

Level 3Level 3Level 3

HTML

Still, inside the initial list where the second level lives, we’ll define two new lists. Each one of them will contain two list items. For each item will specify an h3 element:

1
<ol class="level-2-wrapper">
2
  <li>
3
    ...
4
    <ol class="level-3-wrapper">
5
      <li>
6
        <h3 class="level-3 rectangle">...</h3>
7
      </li>
8
      <li>
9
        <h3 class="level-3 rectangle">...</h3>
10
      </li>
11
    </ol>
12
  </li>
13
  <li>
14
    ...
15
    <ol class="level-3-wrapper">
16
      <li>
17
        <h3 class="level-3 rectangle">...</h3>
18
      </li>
19
      <li>
20
        <h3 class="level-3 rectangle">...</h3>
21
      </li>
22
    </ol>
23
  </li>
24
</ol>

CSS

Thanks again to CSS Grid, we’ll position the nodes.

In the same way, we’ll set the ::before pseudo-element of specific elements for creating the required connections:

1
/*CUSTOM VARIABLES HERE*/
2

3
.level-3-wrapper {
4
  position: relative;
5
  display: grid;
6
  grid-template-columns: repeat(2, 1fr);
7
  grid-column-gap: 20px;
8
  width: 90%;
9
  margin: 0 auto;
10
}
11

12
.level-3-wrapper::before {
13
  content: "";
14
  position: absolute;
15
  top: -20px;
16
  left: calc(25% - 5px);
17
  width: calc(50% + 10px);
18
  height: 2px;
19
  background: var(--black);
20
}
21

22
.level-3-wrapper > li::before {
23
  content: "";
24
  position: absolute;
25
  top: 0;
26
  left: 50%;
27
  transform: translate(-50%, -100%);
28
  width: 2px;
29
  height: 20px;
30
  background: var(--black);
31
}
32

33
.level-3 {
34
  margin-bottom: 20px;
35
  background: var(--level-3);
36
}

Level #4

We’ll need sixteen nodes for the fourth level. These will equally be distributed into four lists.

Each third-level node will include one list:

Level 4Level 4Level 4

HTML

Still, inside the initial list where the second level lives, we’ll define four new lists. Each one of them will contain four list items. For each item will specify an h4 element:

1
<ol class="level-2-wrapper">
2
  <li>
3
    ...
4
    <ol class="level-3-wrapper">
5
      <li>
6
        ...
7
        <ol class="level-4-wrapper">
8
          <li>
9
            <h4 class="level-4 rectangle">...</h4>
10
          </li>
11
          ...
12
        </ol>
13
      </li>
14
      <li>
15
        ...
16
        <ol class="level-4-wrapper">
17
          <li>
18
            <h4 class="level-4 rectangle">...</h4>
19
          </li>
20
          ...
21
        </ol>
22
      </li>
23
    </ol>
24
  </li>
25
  <li>
26
    ...
27
    <ol class="level-3-wrapper">
28
      <li>
29
        ...
30
        <ol class="level-4-wrapper">
31
          <li>
32
            <h4 class="level-4 rectangle">...</h4>
33
          </li>
34
          ...
35
        </ol>
36
      </li>
37
      <li>
38
        ...
39
        <ol class="level-4-wrapper">
40
          <li>
41
            <h4 class="level-4 rectangle">...</h4>
42
          </li>
43
          ...
44
        </ol>
45
      </li>
46
    </ol>
47
  </li>
48
</ol>

CSS

Once more, we’ll set out the ::before pseudo-element of specific elements for associating the fourth-level nodes with their parents:

1
/*CUSTOM VARIABLES HERE*/
2

3
.level-4-wrapper {
4
  position: relative;
5
  width: 80%;
6
  margin-left: auto;
7
}
8

9
.level-4-wrapper::before {
10
  content: "";
11
  position: absolute;
12
  top: -20px;
13
  left: -20px;
14
  width: 2px;
15
  height: calc(100% + 20px);
16
  background: var(--black);
17
}
18

19
.level-4-wrapper li + li {
20
  margin-top: 20px;
21
}
22

23
.level-4 {
24
  font-weight: normal;
25
  background: var(--level-4);
26
}
27

28
.level-4::before {
29
  content: "";
30
  position: absolute;
31
  top: 50%;
32
  left: 0%;
33
  transform: translate(-100%, -50%);
34
  width: 20px;
35
  height: 2px;
36
  background: var(--black);
37
}

Organizational charts and going responsive

Making an organizational chart in CSS responsive is tricky. I remember myself having to reconstruct the markup one or two times until coming up with this version. So, if you plan to create such a chart in CSS, I recommend you follow a mobile-first approach.

With all this in mind, here’s its mobile layout:

Responsive Layout of Organization ChartResponsive Layout of Organization ChartResponsive Layout of Organization Chart

To accomplish this behavior and generate a hierarchy chart design that’s responsive, we have to modify some styles:

1
@media screen and (max-width: 700px) {    
2
  .rectangle {
3
    padding: 20px 10px;
4
  }
5
  
6
  .level-1,
7
  .level-2 {
8
    width: 100%;
9
  }
10
  
11
  .level-1 {
12
    margin-bottom: 20px;
13
  }
14
  
15
  .level-1::before,
16
  .level-2-wrapper > li::before {
17
    display: none;
18
  }
19
  
20
  .level-2-wrapper,
21
  .level-2-wrapper::after,
22
  .level-2::after {
23
    display: block;
24
  }
25
  
26
  .level-2-wrapper {
27
    width: 90%;
28
    margin-left: 10%;
29
  }
30
  
31
  .level-2-wrapper::before {
32
    left: -20px;
33
    width: 2px;
34
    height: calc(100% + 40px);
35
  }
36
  
37
  .level-2-wrapper > li:not(:first-child) {
38
    margin-top: 50px;
39
  }
40
}

We’ve finished our CSS chart!

Congrats, folks! Without writing a single line of JavaScript, we managed to build a fully functional organizational chart.

Let’s remind ourselves of what we did while learning to generate a hierarchy chart design:

Of course, keep in mind that our chart has a specific structure. Depending on your needs, you might want to enrich its content or modify its layout to generate a hierarchy chart design suited to you. If you need something more advanced or dynamic, have a look at some JavaScript libraries like Highcharts.js.

Have you ever created a CSS chart? If so, please share your experience with us!

More CSS charts (sometimes with JavaScript)

If you still need some inspiration, don’t forget to check at my other charts in the Tuts+ archive or do a quick search on CodePen.

As always, thanks a lot for reading!

Leave a comment

Your email address will not be published.