Kontent ♥ Svelte ♥ Custom elements
Tags: kontent, svelte, webdev, typescript
Published: 2021-02-24 18:02:12

###### Photo by [Clément Hélardot](https://unsplash.com/@clemhlrdt?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)
# The power of Kontent
![An animation of your content being published in many places at once.](https://assets-us-01.kc-usercontent.com/ad858591-7c5b-00e9-52c1-796f3aebc535/9cb36347-1f14-400f-a802-dff06c9c7b47/CaaSPublishEverywhere.gif)

[Kontent](https://kontent.ai/) is a headless CMS platform that allows enterprises to [reach more customers](https://kontent.ai/solutions/reach-more-customers), [unify content across the business](https://kontent.ai/solutions/unify-content-across-your-business), and [structure content for future content needs](https://docs.kontent.ai/tutorials/what-is-content-as-a-service), 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](https://docs.kontent.ai/tutorials/manage-kontent/content-modeling/create-and-delete-content-types). 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](https://docs.kontent.ai/tutorials/develop-apps/integrate/content-editing-extensions). 🎉

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.](https://svelte.dev/svelte-logo-horizontal.svg)

[Svelte](https://svelte.dev/) 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](https://svelte.dev/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: 👀

{% youtube AdNJ3fydeao %}
Along with Svelte comes [Sapper](https://sapper.svelte.dev/), an easy way to create static sites running Svelte. Sapper can also quickly deploy to [Vercel](https://vercel.com/), a modern app host with unlimited deployments. 🔮

# By their powers combined...
![A heart with gears symbolizing the combination of Kontent and Svelte.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zgca6okjklvy7ch8ooj.gif)

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](https://docs.kontent.ai/tutorials/introducing-new-and-improved-ui). 🤔

#### Introducing [`kontent-custom-element-app`](https://www.npmjs.com/package/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. 🌯
```jsx
<CustomElement bind:value bind:config bind:disabled>
  // Inputs and values here...
</CustomElement>
```
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.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7gb92qg8vigd48s42gzd.gif)

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.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iriv9tf8kn37kglc50q8.jpg)
###### Photo by [Stefan Steinbauer](https://unsplash.com/@usinglight?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)

KCEA comes with some bonus features!
- **VERCEL** - The template is already set up for deployment to Vercel. Just install the [Vercel CLI](https://vercel.com/download) 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: 🔍
  ```cmd
  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.
  ```
- **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](https://kentico-kontent-konservatory.vercel.app/elements). 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.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xrx8xpxaaz8pt41r26hu.jpg)
###### Photo by [Braden Collum](https://unsplash.com/@bradencollum?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)
In an empty folder for the app:

```
npm init kontent-custom-element-app -n custom-element -s -r
```

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

{% collapsible Script, markup, and style code %}
```jsx
<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>

```
{% endcollapsible %}

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