Learn full-stack web development using fastn in a week
Learn Now
Ahoy, Web Components!
Ahoy, Web Components!
Amit Upadhyay
posted on:
February 25, 2023

ftd is a great language to build UI components in. fastn is easy to learn and author. fastn has a design system, dark mode support. fastn websites are fast as we do server side rendering etc. And we are just getting started, lot more is yet to come.

And yet JS ecosystem is huge. There are far too many ready made components available that we do not want to miss out on them when using fastn-stack.

Today we are pleased to announce support for web components!
Web Components is a suite of different technologies allowing you to create reusable custom elements — with their functionality encapsulated away from the rest of your code — and utilize them in your web apps.
Let's take a look at a demo we have created:
Web Component Demo
Task:
Create
FTD World

So how to use it?

First let's take a moment to appreciate how neatly this demo itself was embedded in this blog post. All I had to do was a line of dependency in FASTN.ftd:
Dependency in FASTN.ftd
-- fastn.dependency: fastn-stack.github.io/ftd-web-component-example
Lang:
ftd
And the following two lines to get the demo:
the blog post page
-- import: fastn-stack.github.io/ftd-web-component-example


-- ftd-web-component-example.demo:
Lang:
ftd
It's kind of complex example, we need a JS dependency for the demo, and it gets neatly download and injected in the right place. And only if I use the component, if I comment out the -- ftd-web-component-example.demo: line, the JS would no longer be needed and would be gone from dependency.

Creating A Web Component

First job is to create the web component itself that you want to use. There is plenty of resource on internet to teach you how to do it, checkout the official React web component guide.

We will start with the MDN tutorial.
class WordCount extends HTMLParagraphElement {
  constructor() {
    super(); // Always call super first in constructor

    // Element functionality written in here
  }
}

customElements.define("word-count", WordCount, { extends: "p" });
Lang:
js
Creating a web-component is this easy. If you want to use it from ftd you have to declare it in a ftd file:
declaring a web-component in ftd
-- web-component word-count:
js: [$assets.files.word-count.js]
Lang:
ftd

What this does is tell ftd about existence of the web-component. Further it tells ftd in what JS file is the web-component is defined. We have used fastn's' assets feature to refer to the JS file.

To use this web-component you can just call -- word-count: somewhere and ftd will do the right thing, JS will get auto included, and web component will get rendered.

Data Across JS and ftd Worlds

A web-component that takes no parameters is not very useful. You would want to pass data to web-component. You would also want to possibly mutate the data from the web-component or JS world, and want fastn world to see the mutations. You may also want to continue to mutate the data in fastn world after web component have been rendered, and have web-component respond to those changes.

All this are possible, the way to think about it is that data that you want to share between the two worlds is "managed" / "owned" by fastn, and from your JS you use fastn APIs to mutate the fastn owned data.

Let's take a look at the web component of this demo:
-- web-component todo-list-display:
string name:
todo-item list $todo_list:
js: [$assets.files.todo.js]
Lang:
ftd

Here we have an argument named name, whose type is string, and the next argument is todo_list of type todo-item list.

As you see todo_list is defined as $todo_list, this means todo_list is a mutable variable. name on the other hand is immutable. So ftd creates a mutable list and an immutable string for the two and passes these to JS.

JS world can get a handle to this data using:
class Todo extends HTMLElement {
    constructor() {
        super(); // Always call super first in constructor

        // get access to arguments passed to this component
        let data = window.ftd.component_data(this);

        // ...
    }
}
Lang:
js

Now you have access to component data, and you can now use data.<var>.get (), .set() functions to manage data from the JS world. You can listen for changes in data on fastn side by using .on_change(function(){ * some code here * }). Checkout the full [source code of our demo] (https://github.com/fastn-stack/ftd-web-component-example/blob/main/todo.js) for more detailed usage.

Go ahead and give it a shot, and come over to Discord in case you face any issues, we would love to hear from you!
Copyright © 2023 - fastn.com