Web Components

Web Components at Ordergroove

Nicolas Moise
Ordergroove Engineering

--

An important part of what we do at Ordergroove is to inject widgets into our client’s online stores that allow online shoppers to subscribe to a product instead of buying it once. This presents a unique set of challenges as we have very little control over the overall setup of our client’s tech stack and the styling rules they have defined. The new Web Components suite has been extremely helpful in solving these challenges. In this article we’ll go over how we’ve managed to leverage Web Components to deliver highly customizable and self-contained front-end functionality to our clients so that they can create their own customized subscription experience. We won’t be spending too much time explaining each specifications but we encourage you to read up on the MDN docs linked in this article if you haven’t.

Web components are now a native feature of most major browsers, making them easy to use alongside major javascript frameworks such as Angular or React. No matter how your markup is loaded, using AJAX or some third-party front-end library, the browser will know what to do when it encounters a custom element in the markup.

Style Scopes and css variables

What took me the longest to get used to with web components and the shadow DOM specification is how they handle styles. Styles inside a shadow tree are scoped to the shadow tree, and don’t affect elements outside the shadow tree. Styles outside the shadow tree also don’t match selectors inside the shadow tree. However, inheritable style properties like color still inherit down from host to shadow tree.

<style>
body { color: white; }

.test { background-color: red; }
</style>
<styled-element>
#shadow-root
<style>
div { background-color: blue; }
</style>
<div class="test">Test</div></styled-element>

In the above example, the div with the “test” class in styled-element would have a blue background-color even though the selector for “background-color: red;” is more specific. The white color is still applied because color is an inherited css property by default and therefore traverses the shadow DOM.

This is helpful to us because it allows us to have a clean canvas to work with and not have our widgets be affected by the css rules defined on our client’s website.

It is still possible however to penetrate the shadow DOM by using css custom properties. A CSS property is declared like this

my-element {
--primary-bg-color: red;
}

and used like this

div {
background-color: var(--primary-bg-color);
}

Custom properties do inherit. This means that if no value is set for a custom property on a given element, the value of its parent is used. The property is only set for the matching selector and its descendants, like any normal CSS.

This allows us to create our own “API” of css properties that we allow merchants to configure wether by declaring the css properties themselves in their website or by using our CMS.

Templates and Slots

While CSS variables allow for a certain level of customization, sometimes our clients want to change the layout of the widget itself. To this end, we have used web component’s templates and slots to enable our clients to create their own customized front-end layouts if they want to override more than just styles directly on the page. Slots make it possible to create and display different text or markup within a web component.

Consider our <og-optin-button> component that allows someone to subscribe to a certain product by clicking on it. By default, the element displays a regular button. If the merchant wants to build something more complex, say making the user click on an image instead of a button, they could re-use the same component and its “default” slot:

Here is some pseudo-code showing how we would build an opt-in button with a slot:

export class OptinButton extends LitElement {  handleClick(ev) {
this.optinProduct();
ev.preventDefault();
}
render() {
return html`
<slot name="default">
<button id="action-trigger"></button>
</slot>
`;
}
}

and how the default slot would be overwritten so that instead of a button, the clickable element is a paragraph:

<og-optin-button product="1234">
<p>Click here to subscribe</p>
</og-optin-button>

In this example the <og-optin-button> encapsulates the click handler and the action of creating a subscription.

Conclusion

Web components enable our clients to create highly customized subscription experiences with very little input from us. Because styles and functionality are encapsulated and scoped in a web component we can be confident that they will work and look as they should no matter which front-end library our clients are using.

Here are a few examples of our components in action:

og-offer and og-optin-status

A standard opt-in/opt-out flow showing wether or not you are subscribed to a product.

og-offer and og-optin-status

og-offer and iu-template slot

A button showing giving you the ability to add a product (either as a one-time purchase or a subscription) to your next upcoming order with the text of the modal customized. This feature allows our merchants to save on shipping costs.

og-offer and iu-template slot

og-upsell-button and og-next-upcoming-order

The same flow as the previous example but with custom text and button label.

og-upsell-button and og-next-upcoming-order

--

--