Although EdgeJS Components draw inspiration from popular front-end frameworks like Vue and Svelte, it’s important to remember that it’s a back-end rendered template engine and can’t replicate all of the principals of the front-end ecosystem.
EdgeJS & Reactivity
The primary principal EdgeJS can’t replicate is reactivity. In front-end applications reactivity allows us to dynamically update the DOM based on state and is usually maintained by one or two way data binding. This works for front-end applications because the state can be maintained client-side in the browser.
With EdgeJS, this becomes difficult to manage because by the time our server-rendered HTML hits the browser EdgeJS has already done it’s job and is out of the picture.
For more advanced components we could reach for a package like HTMX, Hotwire, or Unpoly to allow EdgeJS to become reactive to some extent by utilizing HTML of the wire; which is just a fancy term for sending an API request and getting back new server-rendered HTML in our response.
For now, though, we’ll keep all our reactivity on the client-side and use AlpineJS for our reactivity.
AlpineJS Reactivity
When it comes to defining AlpineJS and adding reactivity with it inside our EdgeJS files, we can treat it and our elements like traditional HTML. AlpineJS won’t load nor execute until it EdgeJS has done it’s thing and our final HTML reaches the browser.
For example, if we were to add reactivity to our layout, let’s say we want to hide the “Home” breadcrumb when it’s clicked instead of following the link, our first step would be to add x-data to the link or one of it’s parents. This attribute allows us to set client-side state by defining an object, which we can modify as needed.
<header x-data="{ breadcrumbs: true }" class="bg-gray-100 p-6 -mx-6 mb-6 rounded-md"> @if (title != 'Home') <a href="/" class="text-xs">Home</a> @endif <h1 class="text-2xl font-bold">{{ titleCase(title) }}</h1> </header>Copied!
- resources
- views
- components
- layouts
- app.edge
Here we’ve initialized AlpineJS on our header element, and giving it a default state with a variable breadcrumbs set to true.
We can then
Bind an event handler to our anchor
Prevent default so our anchor doesn’t follow it’s
hrefMutate our
breadcrumbsstateDetermine whether our anchor is shown via our state
<header x-data="{ breadcrumbs: true }" class="bg-gray-100 p-6 -mx-6 mb-6 rounded-md"> @if (title != 'Home') <a x-show="breadcrumbs" href="/" class="text-xs" @click.prevent="breadcrumbs = false"> Home </a> @endif <h1 class="text-2xl font-bold">{{ titleCase(title) }}</h1> </header>Copied!
- resources
- views
- components
- layouts
- app.edge
Here we’re now using x-show to determine whether our anchor should be displayed. When our breadcrumbs variables is truthy our anchor will display, and when it’s falsy it’ll be hidden.
When our anchor is clicked, we’re then changing our breadcrumbs to false, which will hide the anchor thanks to the x-show.
It’s important to note that none of the markup we added above for reactivity came from EdgeJS; it was all AlpineJS. AlpineJS is our go-to for adding reactivity to our components because it operates on the client-side, while EdgeJS handles server-side rendering and the initial response. Once EdgeJS has completed its job, AlpineJS takes over for client-side reactivity. And, as we’ll see later on, we can also pass data from EdgeJS into AlpineJS further expanding our capabilities.