Sidewind - Tailwind but for state
Sidewind is a light (~4k minified) state management solution designed to work together with Tailwind.css framework.
Sidewind was designed to add interactivity to small sites and it's not a replacement for a full-blown framework. That said, if you don't need much (i.e. routing), it can be enough.
By design, the approach follows the principle of progressive enhancement and your pages will be accessible without JavaScript.
Directives
#Sidewind is composed of a collection of directives that operate on the DOM. I've documented them in detail below.
x-state
and x
#x-state
is a state container and the state is often used by other directives. x
is used for binding values. Consider the example below:
The state can be manipulated using a global setState
:
State can be a complex object:
The calculator example takes this idea further and shows how to handle user interaction.
x
with Attributes
#In addition to binding values, it's possible to bind attributes with x-
:
For classes, it's possible to pass an array to evaluate to produce multiple classes based on expressions:
Default classes are retained as this allows more compact syntax with a fallback:
x-each
#x-each
allows iteration of a list. It has been designed to be used with a template tag.
x-label
#x-label
gives access to parent state and it's useful for sharing information between scopes.
It's also possible to set the parent state within a child. This allows you to nest state within state while being able to mutate it.
The nested behavior works for attributes as well.
Sources
#Sources wrap browser state within a reactive stream that's then mapped to a state.
x-closest
#x-closest
gives you access to the element closest to display top within the selected elements:
x-intersect
#x-intersect
triggers when the element is visible at the viewport. See IntersectionObserver documentation for available options.
In addition to the standard options, there's an once
flag that when set causes the state to be set only once. The behavior is useful for implementing patterns such as lazy loading.
x-interval
#x-interval
wraps setInterval and exposes its delay
parameters. When triggered, it sets state.
x-promise
#It's possible to use the standard fetch() API on top of x-promise
to handle data requests:
- -
In case there's an error, then the Error
object is emitted to error
state:
- -
Examples
#The examples below combine directives to produce complex user interfaces and to handle specific use cases.
Calculator
#TODO List
#Table
#Brand | Color |
Accordion
#Tabs
#Table of Contents
#Loading a Partial
#Code Editor
#Usage
#Local Use
#For now, the easiest way to use Sidewind is to import it to a bootstrap script: import "sidewind";
.
Doing this will activate all included directives and expose setState
in the global scope.
By design, Sidewind is modular and it's possible it will be packaged in a different way in the future so you get only the functionality you want. There's also room for tooling here as it's possible to write a preprocessor that can figure out the right imports based on use per page.
Online Use
#To allow for easy online usage with all functionality, there are versions of Sidewind designed for this purpose - tailwind/sidewind.umd.development.js
and sidewind.umd.production.min.js
. Both include everything and runs the script above.
Example:
<script type="text/javascript" src="https://unpkg.com/[email protected]/dist/sidewind.umd.production.min.js"></script>
Directive API
#All directives of the system have been implemented as plugins. For now, it's best to examine the framework source to see how it all goes together.
Related Approaches
#- Alpine.js provides a similar yet more broad API closer to Angular than Sidewind.
- amp-bind implements data binding and expressions.
- htmx is a complete solution with server integration.
- Mavo implements a DSL on top of HTML for light interactivity.
- Svelte implements a compiler based approach.
- Vue, and especially Vue 3, allows similar usage in the frontend as Sidewind.
License
#MIT.