DEV Community

Cover image for Kontent ♥ Svelte ♥ Custom elements
Yuriy Sountsov
Yuriy Sountsov

Posted on • Updated on

Kontent ♥ Svelte ♥ Custom elements

Photo by Clément Hélardot on Unsplash

The power of Kontent

An animation of your content being published in many places at once.

Kontent is a headless CMS platform that allows enterprises to reach more customers, unify content across the business, and structure content for future content needs, all in one place. As a headless CMS, all content delivery is API-driven, so the same content can show up on any device or channel. 🧠

But what is content? How do you define content? Kontent solves this by creating a reliable structure of items composed of elements. The elements range from plain text to dates to tags to lists of references to other items. Nearly anything can be modeled by combining these elements like LEGO pieces to represent a website, a training manual, a sport directory, you name it. ✨

With great power comes great exploration, and it sometimes happens that you want to model something outside of the known elements. Some examples are geolocation, a video, or a structured list of items. Kontent provides a way to model these and other types of content using custom elements. 🎉

Custom elements run on a host of your choice and only need a browser SDK to communicate with Kontent. This way they have their own UI and their own behavior, and give you freedom to model any content. We will come back to custom elements later... ⌚

The power of Svelte

Svelte logo.

Svelte is a state-of-the-art JavaScript application compiler that takes a lot of boilerplate out of writing browser apps so that you can focus on the reactive user experience. To learn more about Svelte check out the tutorial for a rundown of the basics. 🎓

The best way to deliver a good user experience is to be extremely fast. But why repeat what has already been well said by the creator himself? Just give this a watch: 👀


Along with Svelte comes Sapper, an easy way to create static sites running Svelte. Sapper can also quickly deploy to Vercel, a modern app host with unlimited deployments. 🔮

By their powers combined...

A heart with gears symbolizing the combination of Kontent and Svelte.

With Svelte, we have a way to rapidly create Kontent custom elements. While Svelte takes away the application boilerplate, there is still some boilerplate needed to make custom elements work - initialization, converting a rich object to a string value, reacting to changes in the context (e.g. we want to disable the element when the Kontent item is also disabled), and keeping up with the improving UI. 🤔

Introducing kontent-custom-element-app. 🎆

kontent-custom-element-app (KCEA for short) is a tool that maintains a template to make Kontent custom elements in Svelte as easy as a .svelte component in the src/routes/elements directory using <CustomElement /> to wrap the component's HTML. 🌯

<CustomElement bind:value bind:config bind:disabled>
  // Inputs and values here...
</CustomElement>
Enter fullscreen mode Exit fullscreen mode

KCEA comes with one starter custom element showing different ways to store custom values. It bundles four types of content: text, number, date, and object: 🎭

An animation of the starter element in action.

KCEA also optionally installs two sample custom elements that show more possibilities: color and list. ⚡

Would you like to know more?

A secret door inside a bookshelf.

Photo by Stefan Steinbauer on Unsplash

KCEA comes with some bonus features!

  • VERCEL - The template is already set up for deployment to Vercel. Just install the Vercel CLI and then run vercel in the root of the app. Follow the prompts and you'll be good to share the element outside of localhost! 🌍
  • TYPESCRIPT - The template is also set up for TypeScript, and supports type annotation in components. It will evolve TypeScript support alongside Svelte's TypeScript support. It is a best practice to type value and config within your custom elements. 💪
  • UPDATES - When you update with npm i kontent-custom-element-app, the tool will update template files that have not been changed, and let you know which ones have so you can merge changes manually. An example of what that looks like: 🔍
  File at 'C:\ ... \src\routes\_layout.svelte' has been modified.
  Please manually merge changes from '_layout.svelte' into '_layout.svelte.new' and remove the '.new' extension.
Enter fullscreen mode Exit fullscreen mode
  • USEFUL STUFF - <CustomElement /> has two named slots: loading and invalid. They let you pass in anything that you want to show when the element is loading (between page load and custom element initialization) and when the element's route is visited outside of Kontent. KCEA comes with the components <Loading /> and <Invalid /> to make these slots painless. KCEA also installs the following optional helpful things: 👍
    • A <Filter /> component, which is a filtering text input with autocomplete and other features.
    • An <ObjectTile /> component, which is styled to match asset references in Kontent and helps make custom elements blend into the Kontent UI.
    • A localStorage store to reactively store values in the browser's local storage.
    • A translate store to separate translations from the custom element presentation.
    • A property action to remove some boilerplate around CSS variables on HTML nodes.
  • THE KONSERVATORY - If you want some inspiration, the author maintains a site with many KCEA custom elements at The Konservatory. The Konservatory itself runs on KCEA and thus hosts both a gallery and the elements themselves, showing how KCEA can be a base for more routes and more possibilities! 🤩

TL;DR Quickstart

A spirinter preparing to run.

Photo by Braden Collum on Unsplash

In an empty folder for the app:

npm init kontent-custom-element-app -n custom-element -s -r
Enter fullscreen mode Exit fullscreen mode

Want a basic custom element component to start with? Go to the src/routes/elements directory and add this in a .svelte file:

Script, markup, and style code
<script lang="ts">
  import { fade } from "svelte/transition";

  import CustomElement from "../../shared/components/customElement/customElement.svelte";
  import Invalid from "../../shared/components/customElement/invalid.svelte";
  import Loading from "../../shared/components/loading.svelte";

  let value: string = "";
  let disabled: boolean;
</script>

<CustomElement bind:value bind:disabled>
  <div class="group column root" transition:fade>
    <input
      class="input"
      type="text"
      placeholder="Type here..."
      bind:value
      {disabled} />
  </div>
  <div slot="loading">
    <Loading />
  </div>
  <div slot="invalid">
    <Invalid />
  </div>
</CustomElement>

<style>
  .root {
    padding: 1em;
    background-image: linear-gradient(
      135deg,
      hsl(111, 10%, 98%),
      hsl(111, 35%, 90%)
    );
    border-radius: 0.5em;
  }

  input {
    background: none;
  }
</style>

Enter fullscreen mode Exit fullscreen mode

Let me know down below if you have any questions or would like to start a discussion!

Top comments (0)