# Delightful accordion

Accordions are useful when you want to present key information right away and give interested users the ability to learn more about the topic with a single click.

In this tutorial, you'll create a stylish accordion. Along the way, you'll learn how to combine `::before` and `::after` to create a beautiful effect, how to toggle class and content, and many more.

## Prerequisites

- basic knowledge of HTML
- basic knowledge of CSS
- basic knowledge of JS

## Pretty bullet

Let's start building with pretty bullet. First, create a new file *accordion.html*:
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Beautifull accordion</title>
    <link rel="stylesheet" href="accordion.css">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <script src="accordion.js">
    </script>
</head>
<body>

<div class="accordion">
    <div class="tab">
        <h3 class="outer">
            Coding and programming careers have great earning potential
            <span class="inner"></span>
        </h3>
        <p class="hide">
            One of the strongest and most obvious draws of learning to code is the earning potential for coding and programming professionals. The Bureau of Labor Statistics (BLS) tracks salary and other important workforce information for a variety of careers.
        </p>
    </div>
</div>

</body>
</html>
```

Accordion will be built inside `<div>` with class `accordion`. It contains another `<div>` with class `tab` that contains:
- `<h3 class="outer">`- it contains key information and `<span>` that we'll be used create pretty bullet.
- `<p class="innder">` - it contains more detailed information shown under the key information after click

> At the moment there's a single accordion element. You'll add more of them later on.

After that, create a new file *accordion.css*:

```css
.outer {
  position: relative;
  padding-left: 50px;
  line-height: 40px;
  color: #082c42;
}

.inner {
  position: absolute;
  left: 0;
}

.inner::before {
  content: url("images/button.svg");
  width: 40px;
  height: 40px;
  position: absolute;
}

.inner::after {
  content: "•";
  position: absolute;
  width: 40px;
  text-align: center;
  font-size: 40px;
  color: #082c42;
}
```

Here you have 4 elements on 3 levels:
- `.outer` is a container whose only purpose is to hold some text and `.inner` span.
- `.inner` that holds `::before`/`::after`
- `::before` and `::after`


![single_bullet.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1613727706465/QvJn24eHu.png)


`.outer` is a container for your single bullet. The position of all the absolute positioned elements is based on a non-statically positioned ancestor. By setting the position to relative, you don't move the container, but you make it non-static, so all our absolute positioned elements will be positioned regarding the `.outer`. You set the line-height on `.outer` so all descendants will have the same line-height - that makes it easier to align them. With padding on the left, you get a little breathing room where you will now have space to put your pretty bullet.

`.inner`'s purpose is to contain `::before` and `::after`. It doesn't hold anything but that. Both, `::before` and `::after` will be positioned furthest to the left, thus we position their parent as absolute with `left: 0`.

With the `::before`'s help, we show that pretty 3D button.

Next, create a new directory "images". After that, download the image for the bullet [here](https://gitlab.com/GirlThatLovesToCode/pretty-accordion/-/tree/master/images) and store it inside "images".

Because it's an SVG you're able to set width and height. That works because the element is positioned absolutely. By default, `<span>` is an inline element and you can't define its width or height. But any element that is positioned absolutely, automatically acts as a block element.

`::after` is containing a bullet(•). By making the element the same width and height you make it easier to put it in the middle of the larger circle just with `text-align: center`

> Read about `::before` and `::after` [here](https://girlthatlovestocode.com/css-pseudo-elements-before-and-after)

## Add JavaScript

Once you hace HTML and CSS ready you need to add JavaScript. Add a new file *accordion.js*.
```js
$(document).ready(function() {
    $( ".outer" ).click(function() {
        $(this).closest(".tab").toggleClass("active");
    })
})
```

The color of the middle circle on the bullet should change when clicked on. You can accomplish that by adding another class on the parent tab of the clicked `<h3 class="outer">`. So when the user click on the `<h3 class="outer">`, parent tab is found by `$(this).closest(".tab")`. `toggleClass` is a wonderful jQuery function, that adds or removes a class.

You need to include jQuery and *accordion.js* inside *accordion.html*:
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Beautifull accordion</title>
    <link rel="stylesheet" href="accordion.css">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <script src="accordion.js">
    </script>
</head>
<body>

<div class="accordion">
    <div class="tab">
        <h3 class="outer">
            Coding and programming careers have great earning potential
            <span class="inner"></span>
        </h3>
        <p class="hide">
            One of the strongest and most obvious draws of learning to code is the earning potential for coding and programming professionals. The Bureau of Labor Statistics (BLS) tracks salary and other important workforce information for a variety of careers.
        </p>
    </div>
</div>

</body>
</html>
```

Open *accordion.html* in your browser with Developer's tools opened. Try `toggleClass` functionality by clicking on `<h3 class="outer">`. You'll see that class gets added or removed on the `.tab` when you click. Visualy, there are no changes yet. To do that you have to target the smaller circle with `.inner::after` when `.tab.active` in your css and set it to different color:
```css
.tab.active .inner::after {
    color: #bfd7ed;
}
```

Now, if you click on it repeatedly, it alternates colors based on class `active`.

## Hide detailed content

Detailed content should not show at first. It should slowly slide down when you click on `<h3 class="outer">` (when the tab is `active`) and slide back up when you click on it again.

To do that you need to add a new class to *accordion.css*:
```css
.hide {
    display: none;
}
```

To add slide effect you need to use `slideToggle` function. Edit your *accordion.js* to look like this:
```js
$(document).ready(function() {
    $( ".outer" ).click(function() {
        $(this).closest(".tab").toggleClass("active");
        $(this).siblings(".hide").slideToggle("slow");
    })
})
```
The added line is pretty similar to the previous one. It finds a sibling of the clicked element that has a class `hide` and toggles the slide. Now, when you click on the `.outer`, the bullet changes color, and the content either opens or closes.

![single.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1613727727797/3aI94CyPK.png)

## Accordion

You can't really call it an accordion if it contains only one tab. so let's fix this. Edit your *accordion.html* to look like this:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Beautifull accordion</title>
    <link rel="stylesheet" href="accordion.css">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
    <script src="accordion.js">
    </script>
</head>
<body>

<div class="accordion">
    <div class="tab">
        <h3 class="outer">
            Coding and programming careers have great earning potential
            <span class="inner"></span>
        </h3>
        <p class="hide">
            One of the strongest and most obvious draws of learning to code is the earning potential for coding and programming professionals. The Bureau of Labor Statistics (BLS) tracks salary and other important workforce information for a variety of careers.
        </p>
    </div>
    <div class="tab">
        <h3 class="outer">
            Demand remains strong for coding-related jobs
            <span class="inner"></span>
        </h3>
        <p class="hide">
            When compared to the national average of five percent growth, you can see that a handful of positions are outpacing a lot of other careers. Computer programmers are an interesting outlier from this group, but some believe these projections are influenced by computer programming skills blending into other related in-demand tech roles.         </p>
    </div>
    <div class="tab">
        <h3 class="outer">
            Coding ability gives new perspective to problem-solving
            <span class="inner"></span>
        </h3>
        <p class="hide">
            Coding, in its most basic terms, is just assigning a computer a task to do based on the logical guidelines you’ve outlined. Highly complex tasks are essentially a collection of smaller operations once you break them down. This methodical and logic-heavy approach to problem-solving can be a boon for figuring out problems beyond a coding challenge.         </p>
    </div>
</div>

</body>
</html>
```

Your HTML stayed the same, except that you added two more tabs inside the accordion. Check your browser, you'll see that it still works as intended.


![multiple.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1613727752660/Kt8O2dVHN.png)

There's only one problem - it doesn't look like an accordion. It looks like a bunch of text that can be shown or hidden. To improve that, let's create a line on the left side that will connect all tabs.



## Line on the left

The line should run at the middle of your bullets and be covered by them where necessary. If you want the freedom to move it as you like, you can't create it as a border but as its own element. You'll use `::before` for creating it. Add these classes to *accordion.css*:

```css
.accordion {
    position: relative;
}

.accordion .tab::before {
    border-left: solid #979797 1px;
    content: '';
    position: absolute;
    left: 20px;
    top: 0;
    bottom: 0;
    z-index: -1;
}
```
Although it looks like one line, it's created by multiple lines - from one tab to another. You want to take them(it) out of the page flow, so they're positioned absolutely. As mentioned before, you need to position an ancestor as `relative` for this to work - `.accordion {position: relative;}`. If you skip that step, you'll see that the line stretches through the whole browser.

The `::before` doesn't have any content, just left border. `left: 20px;` positions it in the middle of the circle.
`z-index: -1;` puts it behind the bullet and `top: 0; bottom: 0;` stretches it from beginning to the end of the tab.

It looks pretty when it's closed, right? Not so much when it's opened.

![line_over_text.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1613727769842/UAqyNY58K.png)

Let's fix that.

## Small CSS repairs

You want to move the detaild text to the right, so it aligns with the key point text. To do that, add padding to `.hide` class inside *accordion.css*:

```css
.hide {
    padding-left: 50px; /* newly added */
    display: none;
}
```

You also want to make the accordion narrower. To do that, limit max width of `.accordion` to *800px* inside *accordion.css*:

```css
.accordion {
    position: relative;
    max-width: 800px;
}
```

![css_fixes.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1613727789931/WxwIwj32Y.png)

This looks much better, doesn't it?

## Only one tab opened

For now, if you click on a tab, it opens and if you click on it again, it closes. Clicking on another tab has no impact on all the other tabs. But there should be only one tab open at a time. When you click on one tab it should open and all the others should close.

Once again, edit *accordion.js*:
```js
$(document).ready(function() {
    $( ".outer" ).click(function() {
        $(this).closest(".tab").toggleClass("active");
        $(this).siblings(".hide").slideToggle("slow");
        $(this).closest(".tab").siblings(".tab.active").find(".hide").slideUp("slow") // added
        $(this).closest(".tab").siblings(".tab.active").removeClass("active") // added
    })
})
```

From the `<h3>` on which you clicked, it moves to its tab parent. Then it finds tab's siblings that have class `active`. If you did that correctly, there shouldn't be more than one active tab. After that, it slides up the child with class `hide`, and then it removes the `active` class from the found tab.

If you play around a little in your browser, you can see that now there is always max one tab open, but you can also close the open one.

![one_open.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1613727806980/j0ZgA0VOW.png)

If you paid attention, you'll notice that you're not finished yet. There's a little skip when the text is sliding up and it doesn't look good.

That's because you have an unwanted margin for `<h3>`. It is added by the browser.

## Last CSS fixes

Because there's only one thing on your page, you won't include a whole file but just remove the border instead. Add `margin: 0;` to `.outer` inside *accordion.css*:

```css
.outer {
  position: relative;
  padding-left: 50px;
  line-height: 40px;
  color: #082c42;
  margin: 0; /* newly added */
}
```

Another browser-applied border that makes things look wrong is `margin-top` on `.hide`. Set this to 0, too:

```css
.hide {
    padding-left: 50px;
    display: none;
    margin-top: 0; /* newly added */
}

```

As you can see, you set the margin of `.outer` to 0 and when the text is closing it doesn't skip anymore. You also broke design, but that's easily fixable. Add a little padding at the bottom of `.outer`:

```css
.outer {
    position: relative;
    padding-left: 50px;
    line-height: 40px;
    color: #082c42;
    cursor: pointer;
    margin: 0;
    padding-bottom: 15px; /* newly added */
}
```

Now you created another problem. Because of the padding, the line on the left side doesn't end with the last bullet. Padding should be applied for all the bullets except for the last one. You can find the last tab with `:last-child` and apply 0 padding at the bottom of its child `.outer`.

```css
.tab:last-child .outer{
    padding-bottom: 0;
}
```

And this is it! Here's your pretty accordion:

![finnished.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1613727826763/QiYv0UM1j.png)

> In a real application, you'd probably want to use a CSS Reset file like [this one](https://github.com/murtaugh/HTML5-Reset/blob/master/assets/css/reset.css) or maybe a [simpler one](https://github.com/vladocar/CSS-Mini-Reset/blob/master/CSS-Mini-Reset.css).

## Conclusion

You have a pretty accordion to show, but you also learned so many things that you can use anywhere.
You learned:
- How to combine `::before` and `::after` to create a beautiful effect
- How to toggle class
- How to apply different style by adding a class with JS
- How to toggle hidden/shown content
- That sometimes browsers break your design by applying their own

I hope you'll be able to create many more beautiful things with the knowledge you gained in this tutorial.

Whole code is visible [here](https://gitlab.com/GirlThatLovesToCode/pretty-accordion)

> Text taken from: https://www.rasmussen.edu/degrees/technology/blog/why-learn-to-code/


