Alpine.js CSP¶
Alpine.js is a lightweight JavaScript framework that brings client-side interactivity to your page. Compared with writing vanilla JavaScript, Alpine.js CSP simplifies many tasks and brings your code into a maintainable structure. However, basic JavaScript knowledge is still required. Compared with htmx, Alpine.js is for client-side interactivity, while htmx is for client-server interaction.
The standard version of Alpine.js isn’t compatible with the CSP header. Therefore, xlwings Server includes the CSP build by default. The main difference is that you place all your code outside of the HTML tags, meaning the standard Alpine.js documentation needs adaptation for use.
xlwings Server provides a helper function, registerAlpineComponent()
, which makes it easier to connect the HTML with the JavaScript part.
Throughout the rest of this page, when we refer to Alpine or Alpine.js, we mean the CSP build of Alpine.js.
First Steps¶
To use Alpine.js, add the x-data
directive to the part of your HTML that you want to bring to life. This converts the specified section into an Alpine component. For optimal performance, apply it to an HTML tag that wraps the smallest possible amount of code.
Let’s have a look at the first example under app/templates/examples/alpine
. For clarity, the Bootstrap classes that are used in the example aren’t shown here so that we can concentrate on the Alpine.js directives:
<div x-data="visibility">
<button x-text="label" @click="toggle"></button>
<span x-show="isOpen">The Magic of Alpine.js!</span>
</div>
x-data
turns thediv
into an Alpine component.x-text
sets the text content of an element, in our case the button, to the value oflabel
.x-show
shows or hides an element based on whetherisOpen
istrue
orfalse
.@click
runs thetoggle()
method when the button’s click event is fired (i.e., when the button is clicked).
To bring the Alpine component to life, we have to implement the visibility
object with the isOpen
and label
properties and the toggle()
method. To finalize, the component has to be registered by calling registerAlpineComponent()
. This function connects x-data
name with the JavaScript object.
const visibility = {
isOpen: false,
label: "Show",
toggle() {
this.isOpen = !this.isOpen;
this.label = this.isOpen ? "Hide" : "Show";
},
};
registerAlpineComponent("visibility", visibility);
Where to write the Alpine.js JavaScript code¶
The JavaScript sample code lives in app/static/js/core/examples.js
.
If you only have a few Alpine components, you can place the JavaScript code into app/static/js/main.js
.
If your task pane turns into a complex app, you could also introduce a proper structure along the following lines:
app/
static/
js/
components/
auth/
___.js
dashboard/
___.js
shared/
___.js
___.js
You could load these JS files on-demand in your templates via
{% block extra_head %}
...
{% endblock extra_head %}
If you want to load the code in base.html
, make sure to load alpinejs-csp-boilerplate.js
first before your own code and finally vendor/@alpinejs/csp/dist/cdn.min.js
.
Directives¶
Here are the most useful Alpine directives (click on the name to get to the official docs):
x-data
: initialize an Alpine component.x-show
: show/hide an element.x-bind
: set attributes on an element. This is usually used via the colon shorthand, e.g.,:value
or:class
.x-on
: listen for browser events. This is usually used via the@
shorthand, e.g.,@click
.x-text
: set the text content of an element.x-if
: adds/removes a block of HTML from the page completely (doesn’t just show/hide it).x-init
: runs code when the Alpine component is initialized.
For a complete list, see the official docs.
Init and destroy functions¶
If your object contains an
init()
method, Alpine executes it before it renders the component. If your component also has anx-init
directive,init()
function will be called first.If your object contains a
destroy()
method, Alpine executes it before cleaning up the component.
See the official docs.
Magics¶
Magic properties and methods start with a $
, e.g., $el
and they give you access to a few powerful features. With the CSP build, you have to use them via this
, e.g., to access the current DOM element:
this.$el
You could use this.$el
to get the button element that triggered the click event. You can see $el
in action below in the section about Event object.
For an overview of all magic properties, see the official docs.
Keyboard shortcuts¶
Alpine.js makes it easy to build keyboard shortcuts. If you want them to be global, you need to include the window
modifier so that Alpine registers the event listener on the window
object instead of on the element itself. For example, to focus on a form input element when typing /
, it’s enough to add this attribute to the respective element:
<input @keydown.window.slash.prevent="focus" />
with the corresponding JavaScript method:
focus() {
this.$el.focus();
}
To see the full context and give it a try, have a look at the “Names” example under app/templates/examples/alpine
.
Let’s go through how everything works:
keydown
: this event fires when you press any keywindow
: attaching the event to thewindow
object allows you to listen to it globallyslash
: it listens for the/
keyprevent
: this prevents the default behavior, as otherwise it would write/
into the text box.
For an overview of all available modifiers for your event listeners, have a look at the official docs.
Event object¶
If you have advanced needs, you can access the event
object when handling an event. Let’s have a look at the JavaScript part of the “Slider” example under app/templates/examples/alpine
:
const slider = {
percentage: 50,
update() {
this.percentage = this.$el.value;
},
};
Instead of using the $el
magic, you could also use the event
object directly like so:
const slider = {
percentage: 50,
update(event) {
this.percentage = event.target.value;
},
};
Alternatively, you could also use Alpine’s $event
magic:
const slider = {
percentage: 50,
update() {
this.percentage = this.$event.target.value;
},
};
However, using the CSP build, explicitly passing the event
means less typing and is arguably more elegant.
Alpine.js vs Alpine.js CSP build¶
The CSP build doesn’t support everything from standard Alpine.js. Here’s a list of limitations:
x-model
isn’t supported. Instead, use a combination of@input
and:value
.When you work with AI, prompt it to deliver the solution using
Alpine.data()
, as this is essentially what the CSP build uses behind the scenes.
Alternatives¶
If you don’t want to use Alpine.js, you may want to have a look into one of the following alternatives: