This is a collection of custom plugins for Alpine.js.
This plugin adds the x-include
directive that enables
including an Alpine "component" in an HTML file that uses Alpine.
Each component is defined in a separate HTML file.
They can be included any number of times as follows:
<div x-include="component-name" x-data="{properties-to-pass}"></div>
There must be a file similar to the one below named component-name.html
.
This inserts the HTML of the component and
makes the x-data
properties available to it.
The following is an example of defining such a component
in the file progress-bar.html
.
This must be served by an HTTP server rather than opening it as a file
in order to avoid CORS issues.
<!--
This component renders a progress bar.
Instances can specify the following x-data properties:
- min - minimum value; optional number; default 0
- max - maximum value; optional number; default 100
- value - value to display; required number
- bgColor - background color of bar; optional string; default gray
- color - foreground color of bar; optional string; default green
- low - optional number; no default
- lowColor - bar color if value <= low; optional string; no default
- high - optional number; no default
- highColor - bar color if value >= high; optional string; no default
-->
<!-- Using a nested selector provides CSS scoping.
Use the name of the component as the outer CSS class. -->
<style>
.progress-bar {
height: 2rem;
position: relative;
width: 20rem;
& .bar {
height: 100%;
}
& .value {
color: white;
font-family: sans-serif;
/* centers text in .progress-bg */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
</style>
<script>
// Placing all the functions in one global object reduces name conflicts.
const ProgressBar = {
getBarStyle(data) {
const { color, low, lowColor, high, highColor, value } = data;
const barColor =
typeof low !== "undefined" && lowColor && value <= low
? lowColor
: typeof high !== "undefined" && highColor && value >= high
? highColor
: typeof color === "undefined"
? "green"
: color;
return `background-color: ${barColor}; width: ${this.getPercent(data)}%`;
},
getPercent(data) {
const { min, max, value } = data;
const minimum = typeof min === "undefined" ? 0 : min;
const maximum = typeof max === "undefined" ? 100 : max;
return Math.round(((value - minimum) / (maximum - minimum)) * 100);
},
validate(data) {
// Check for required properties.
if (typeof data.value === "undefined") {
throw new Error("progress-bar requires value");
}
},
};
</script>
<!-- The "props" are supplied by x-data on instances. -->
<div
class="progress-bar"
:style="`background-color: ${typeof bgColor === 'undefined' ? 'gray' : bgColor}`"
x-init="ProgressBar.validate($data)"
>
<div class="bar" :style="ProgressBar.getBarStyle($data)"></div>
<div class="value" x-text="ProgressBar.getPercent($data)"></div>
</div>
Here is an example of using the component defined above:
<html lang="en">
<head>
<title>Alpine Component Demo</title>
<style>
.temperature {
display: flex;
align-items: center;
gap: 1rem;
margin-top: 1rem;
}
</style>
<script
defer
src="https://cdn.jsdelivr.net/gh/mvolkmann/[email protected]/include.js"
></script>
<script
defer
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"
></script>
</head>
<body x-data="{show: true, temperature: 50}">
<!-- "value" is a "getter" so it can use other state.
x-data on instances like this is only for "props". -->
<div
x-include="progress-bar"
x-data="{
get value() { return temperature; },
low: 40,
lowColor: 'blue',
high: 80,
highColor: 'red'
}"
></div>
<label class="temperature">
Temperature
<input type="range" min="0" max="100" x-model="temperature" />
<span x-text="temperature"></span>
</label>
<div
x-include="progress-bar"
x-data="{
min: 20,
max: 80,
value: 30,
bgColor: 'coral',
color: 'cornflowerblue',
}"
></div>
</body>
</html>
This plugin simplifies inserting the values of JavaScript expressions into text content.
Without this plugin, you might write the following:
<span x-text="some-expression"></span>
With this plugin, you can write the following instead:
{some-expression}
In order for this to work:
-
Add the following
script
tag before the one foralpinejs
:<script defer src="https://cdn.jsdelivr.net/gh/mvolkmann/[email protected]/interpolate.js" ></script>
-
Add the
x-interpolate
directive to any element whose contents should be searched for interpolations. -
Optionally choose different delimiters. Any characters can be used as long as an even number of them are specified. For example, to use
{{some-expression}}
, add the followingscript
tag:<script> alpineInterpolateDelimiters = "{{}}"; </script>