Skip to content

This is a collection of custom plugins for Alpine.js.

License

Notifications You must be signed in to change notification settings

mvolkmann/alpine-plugins

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

alpine-plugins

This is a collection of custom plugins for Alpine.js.

x-include

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.

x-include demo

<!--
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>

x-interpolate

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:

  1. Add the following script tag before the one for alpinejs:

    <script
      defer
      src="https://cdn.jsdelivr.net/gh/mvolkmann/[email protected]/interpolate.js"
    ></script>
  2. Add the x-interpolate directive to any element whose contents should be searched for interpolations.

  3. 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 following script tag:

    <script>
      alpineInterpolateDelimiters = "{{}}";
    </script>

About

This is a collection of custom plugins for Alpine.js.

Resources

License

Stars

Watchers

Forks

Packages

No packages published