DEV Community

Cover image for Web Component ideas: Making an if element
Ben Taylor
Ben Taylor

Posted on • Edited on

Web Component ideas: Making an if element

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

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:

<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>
Enter fullscreen mode Exit fullscreen mode

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:

<template id="ben-if">
  <style>
    :host {
      display: none;
    }
  </style>
  <slot></slot>
</template>
Enter fullscreen mode Exit fullscreen mode

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.

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);
Enter fullscreen mode Exit fullscreen mode

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:

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

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.

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

  attributeChangedCallback(name, oldValue, newValue) {
    // ...
    this.checkIf();
  }
Enter fullscreen mode Exit fullscreen mode

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

Interested in Web Components?

I'm speaking about Practical Uses for Web Components at Web Directions: 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

Top comments (2)

Collapse
 
tylermorales profile image
Tyler Morales

Is there a more functional approach to writing the JavaScript as compared to the classes?

Collapse
 
taybenlor profile image
Ben Taylor

The Web Component API is pretty strongly bound to classes. For example, registering a custom element ensures the argument is a class. There are some libraries which will help you compile to Web Components as a target. But there’s nothing like (for example) a React pure function component.