Web Component ideas: Making an if element
Tags: webdev, javascript
Published: 2021-08-30 12:07:51

I'm a big fan of Web Components, they're super useful. But have you ever thought of using them as an if statement?

![Screen Recording 2021-08-30 at 9.23.59 pm](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u02dmjaku8uqqygvwww2.gif) 

If the user selects the cat radio element, then the "Yep, cats are the best!" message will be displayed. If they select the dog radio element, then the other message will be displayed.


## Web Components for authoring content

People tend to think about web development as a way of building apps. But that misses a big category of what people do on the web: making documents! Back in the day people used to write raw HTML straight to their web servers. But now we write in a CMS or a blogging system like this one. In those sorts of systems you tend to use a rich text editor, or markdown.

HTML is still really good for making documents though! If you want to make something really custom, HTML is a great tool. Using Web Components lets you do even more interesting things, things that go beyond just bold, italic and headings. You can create custom logic as well! That's the kind of stuff that _hypertext_ should be used for.

If you're maintaining a website, blog, or CMS with authors who like to do interesting things you should try out Web Components. They're easy to write and they're custom just for your purpose!


## What does the HTML look like?

In this example I wanted to create a kind of if-statement that changed which content was displayed based on which option was selected in some radio buttons. I started by writing out the HTML, so I could get a sense of how it should work:

```html
<label>
  <input type="radio" name="animal" value="cat">
  Cat
</label>

<label>
  <input type="radio" name="animal" value="dog">
  Dog
</label>

<ben-if name="animal" value="cat">
  <p>
    Yep, cats are the best!
  </p>
  <img src="http://placekitten.com/200/100" alt="kitten">
</ben-if>

<ben-if name="animal" value="dog">
  <p>
    Dogs are pretty good, but have you tried cats?
  </p>
</ben-if>
```

You can see here I'm creating a custom element called `ben-if` which has two attributes `name` and `value`. The idea is that if the matching radio box is ticked, then the if statement will show. Otherwise it will be hidden.

Because they're just HTML, I can put other HTML elements inside them without any issues. If you were using a markdown parser that allowed HTML, you could also put markdown inside the HTML. This makes it super flexible, so I could make lots of different sorts of things with just this one trick.

There's a lot of other benefits here to using web components. You don't need to include any third party libraries, and you don't need to set up a rendering context. It will work across any framework, including React, Vue, Svelte etc. It's part of the way the browser works!


## Creating the template

To write my web component, I needed a template. This template is really simple because it doesn't do much. This is the HTML for it:

```html
<template id="ben-if">
  <style>
    :host {
      display: none;
    }
  </style>
  <slot></slot>
</template>
```

In the styling here the `:host` element refers to the web component I'm building. I've made it `display: none` so that it is hidden by default. The `<slot></slot>` element is where child content will be put inside this element.


## Writing the javascript

The logic for this is a little bit more complicated. First I've set up some boilerplate. This renders the template I created into the web component, and keeps track of the `name` and `value` attributes. It also defines the custom element I've created as `ben-if`.

```js
class IfElement extends HTMLElement {
  static get observedAttributes() {
    return ['name', 'value'];
  }
  
  constructor() {
    super();

    this.attachShadow({mode: 'open'});
    const template = document.getElementById('ben-if');
    const clone = template.content.cloneNode(true);
    this.shadowRoot.appendChild(clone);
  }
  
  attributeChangedCallback(name, oldValue, newValue) {
    this[name] = newValue;
  }
}

// Define this custom element
customElements.define('ben-if', IfElement);
```

Now that I've got the boilerplate out of the way, it's time to do the logic. I created a `checkIf` method on my `IfElement` to show or hide my element:

```js
  checkIf() {
    const radio = document.querySelector(`[name="${this.name}"][value="${this.value}"]:checked`);
    if (radio) {
      this.style.display = "block";
    } else {
      this.style.display = "none";
    }
  }
```

This will query the document to find a checked element with the matching `name` and `value`. If there is one, it will set the element to `display: block`. If there isn't one it will set the element to `display: none`.

Now we just need to wire that call up. I put it in two places:

1. As an event that gets called any time a change event happens on the page

2. After the attributes change.

```js
// ...
  constructor() {
    // ...
    document.addEventListener('change', () => {
      this.checkIf();
    });
  }

  attributeChangedCallback(name, oldValue, newValue) {
    // ...
    this.checkIf();
  }
```

And that's everything! Now it should all work together. Here's a codepen:

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


## 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)