Web Component ideas: Building a carousel
Tags: webdev, javascript
Published: 2021-08-31 13:37:23

Carousels are a useful component for displaying a series of images (or really any media). People often use carousels off the shelf, but they're quite easy to build yourself! In this post I'll go through building a Web Component for a carousel.

![Screen Recording 2021-08-31 at 10.46.44 pm](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93lcbv765k34nciqgc7e.gif)

You can see here that as you click the next and previous buttons it scrolls through a series of images.

## Building elements that don't exist

Web Components are handy tools for abstracting out common patterns in HTML. There's lots of user interface patterns that are common on the web but don't have their own elements. Instead you have to build them up yourself from other elements.

If you find yourself repeating HTML, or the complexity gets too much, it can be handy to abstract out the complexity. By creating a Web Component you can create a neat abstraction that becomes reusable and easier to understand. Plus it makes your HTML much tidier!

## What does the HTML look like?

This Web Component is rather simple, it doesn't have any attributes - you just put some elements inside it.

```html
<ben-carousel>
  <img src="http://placekitten.com/360/200">
  <img src="http://placekitten.com/300/200">
  <img src="http://placekitten.com/420/200">
</ben-carousel>
```

The idea here is to stick to standard elements as much as possible and to keep it simple. The carousel is going to be in charge of displaying the content like a carousel. Then the content itself can be anything! In this case I've put in three images of cats at different sizes.

A big benefit of this approach, using Web Components, is that I can put any HTML content inside my carousel. It's just HTML! Plus I can use it in any website, no matter the library. Sticking to standards often makes things easier.


## Creating the template

To begin with I wrote down the elements I'd need to create this carousel:

```html
<template id="ben-carousel">
  <button>Prev</button>
  <slot></slot>
  <button>Next</button>
</template>
```

You can see here that I've got two buttons, one for going left and one for going right. Then I've put a `slot` element in, this is where the content inside will go. But this isn't quite enough for it to look like a carousel. Right now it looks like this:

![Screen Shot 2021-08-31 at 11.09.30 pm](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1cwb1t6wwirmqpxztk9s.png)

So we'll need to add some styling. Once we've got it looking like a carousel we can move on to making it work like a carousel.

Here's how I styled it:

```html
<template id="ben-carousel">
  <style>
    :host {
      display: block;
    }
    
    #container {
      display: flex;
    }
    
    #images {
      display: flex;
      flex-shrink: 1;
      overflow: scroll;
    }
  </style>
  <div id="container">
    <button id="prev">Prev</button>
    <div id="images">
      <slot></slot>
    </div>
    <button id="next">Next</button>
  </div>
</template>
```

First lets look at the extra elements I added. I've created a `div` to wrap all of the other elements, this will be useful for layout. Then I've added another `div` for the images, this will help to control how much of them is displayed.

You can also see here that I've given every element an `id`. When you're working with Web Components the HTML and CSS is all scoped to within the component. So you can use `id` as much as you please, it won't overlap with others on your page. This makes it much easier to write JavaScript and CSS.

Now lets look at the style here. The first part makes it so the element displays as a `block` element:

```css
:host {
  display: block;
}
```

Next up I've styled the outer container to use `display: flex`:

```css
#container {
  display: flex;
}
```

This makes it so that the three child elements (`#prev`, `#images`, and `#next`) all display next to eachother horizontally. Which is key to the whole layout!

Finally we're looking at the `#images` container. Here I use `flex-shrink: 1` to make it so the `#images` container will shrink down when the width of its parent is constrained.

```css
#images {
  flex-shrink: 1;
  display: flex;
  overflow: scroll;
}
```

I've also used `display: flex` here to make the children of the `#images` container (the images) all display next to eachother in a line. Finally `overflow: scroll` says that the `#images` container should create a scrollbar if its content has overflowed it.

The result looks like this:

![Screen Shot 2021-08-31 at 11.21.59 pm](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ytkty12gjg620dr7n5so.png)
 
That's just about everything! The only part we don't have is the buttons.

## Wiring up the buttons

To wire up the buttons we'll need to write some JavaScript. First we'll set up some boilerplate for creating the carousel element:

```js
class CarouselElement extends HTMLElement {
  constructor() {
    super();

    this.attachShadow({mode: 'open'});
    const template = document.getElementById('carousel');
    const clone = template.content.cloneNode(true);
    this.shadowRoot.appendChild(clone);
  }
}

customElements.define('ben-carousel', CarouselElement);
```

Now we want to wire up the events. Because we've already given each of our elements an `id` this is rather easy. First we get each of the elements we need from the `shadowRoot`:

```js
// ... inside the constructor

const images = this.shadowRoot.getElementById('images');
const prev = this.shadowRoot.getElementById('prev');
const next = this.shadowRoot.getElementById('next');

```

Then we set up click handlers that scroll the images container:

```js
// ... inside the constructor

prev.addEventListener('click', () => {
  images.scrollLeft -= 100;
})
    
nextButton.addEventListener('click', () => {
  images.scrollLeft += 100;
})
```

And bingo bango we've got a scrolling carousel!

{% codepen https://codepen.io/taybenlor/pen/YzQwbGb %}

## Interested in Web Components?

I'm speaking about [Practical Uses for Web Components](https://webdirections.org/code/speakers/ben-taylor.php) at [Web Directions: Code](https://webdirections.org/code/) on September 17 & 24 2021. If you're interested you can use the voucher `bensentme` to get 20% off!

![DElgPan_Fq7SbJfAKW_1Q_L_U2HSzzpnKuwR1onC9M3VGLRykUod7atRXJTePP4wGCk3H995w7W7-BfXrNnw8jL52tDBrrmSASqYKUIT0i0nAWDRo59G0OPiRF_UVEP0A4tVGGxS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d19ypndwqrlp9wydz8t3.png)