Alpine JS is a lightweight, modern, and reactive JavaScript framework that lets you add interactivity to your web pages without writing a lot of code. Alpine JS is inspired by Vue, but it does not require a build step or a virtual DOM. Instead, it uses a declarative syntax that you can write directly in your HTML markup.

In this post, we will learn how to use Alpine JS by building three simple applications:

  • A weather app that makes an API request and displays the current temperature and weather condition for a given city.
  • A counter app that changes the UI after a user pushes a button.
  • A contact form that takes in user input and sends it to an API.

Setting up Alpine JS

To use Alpine JS, all you need to do is add a script tag to your HTML file that points to the Alpine JS CDN. For example:

<script src="https://cdn.jsdelivr.net/npm/alpinejs@3"></script>

Alternatively, you can download Alpine JS from its official website and include it locally.

Building a weather app with Alpine JS

The first application we will build is a weather app that makes an API request to the OpenWeatherMap API and displays the current temperature and weather condition for a given city. To follow along, you will need to sign up for a free API key from OpenWeatherMap.

HTML structure

The HTML structure of our weather app is very simple. We have a div element with an x-data attribute that declares a new Alpine JS component and its data. The data consists of four properties: city, apiKey, temp, and condition. The city property holds the name of the city we want to get the weather for, the apiKey property holds our OpenWeatherMap API key, and the temp and condition properties will hold the temperature and weather condition that we will get from the API.

We also have an input element with an x-model attribute that binds its value to the city property, and a button element with an x-on:click attribute that listens for a click event and calls a function named getWeather. This function will make the API request and update the temp and condition properties.

Finally, we have two span elements with x-text attributes that display the values of the temp and condition properties.

<div x-data="{ city: 'Toronto', apiKey: 'YOUR_API_KEY', temp: '', condition: '' }">
  <input type="text" x-model="city">
  <button x-on:click="getWeather">Get Weather</button>
  <span x-text="temp"></span>
  <span x-text="condition"></span>
</div>

JavaScript logic

The JavaScript logic of our weather app is written inside the x-data attribute as a plain JavaScript object. We define a method named getWeather that uses the fetch API to make a GET request to the OpenWeatherMap API with the city and apiKey parameters. We then parse the response as JSON and extract the temperature and weather condition from the data. We convert the temperature from Kelvin to Celsius and round it to one decimal place. We also capitalize the first letter of the weather condition. We then assign the temperature and weather condition to the temp and condition properties, which will automatically update the UI.

<div x-data="{ city: 'Toronto', apiKey: 'YOUR_API_KEY', temp: '', condition: '', getWeather() { fetch(`https://api.openweathermap.org/data/2.5/weather?q=${this.city}&appid=${this.apiKey}`) .then(response => response.json()) .then(data => { let kelvin = data.main.temp; let celsius = kelvin - 273.15; celsius = celsius.toFixed(1); let weather = data.weather[0].main; weather = weather.charAt(0).toUpperCase() + weather.slice(1); this.temp = celsius + '°C'; this.condition = weather; }) .catch(error => console.error(error)); } }">
  <input type="text" x-model="city">
  <button x-on:click="getWeather">Get Weather</button>
  <span x-text="temp"></span>
  <span x-text="condition"></span>
</div>

Result

The result of our weather app is a simple and interactive web page that displays the current temperature and weather condition for a given city. You can change the city name in the input field and click the button to get the weather for that city.

Building a counter app with Alpine JS

The second application we will build is a counter app that changes the UI after a user pushes a button. This app will demonstrate how to use Alpine JS to manipulate the state and the UI of a component.

HTML structure

The HTML structure of our counter app is very simple as well. We have a div element with an x-data attribute that declares a new Alpine JS component and its data. The data consists of one property: count, which holds the value of the counter.

We also have a button element with an x-on:click attribute that listens for a click event and increments the count property by one. We also have a span element with an x-text attribute that displays the value of the count property.

<div x-data="{ count: 0 }">
  <button x-on:click="count++">Increment</button>
  <span x-text="count"></span>
</div>

JavaScript logic

The JavaScript logic of our counter app is very minimal. We only need to declare the count property in the x-data attribute and increment it by one in the x-on:click attribute. Alpine JS will automatically update the UI whenever the count property changes.

<div x-data="{ count: 0 }">
  <button x-on:click="count++">Increment</button>
  <span x-text="count"></span>
</div>

Result

The result of our counter app is a simple and interactive web page that displays a counter that increases by one every time the button is clicked.

Building a contact form with Alpine JS

The third and final application we will build is a contact form that takes in user input and sends it to an API. This app will demonstrate how to use Alpine JS to handle user input and form submission.

HTML structure

The HTML structure of our contact form is a bit more complex than the previous apps. We have a form element with an x-data attribute that declares a new Alpine JS component and its data. The data consists of four properties: name, email, message, and response. The name, email, and message properties hold the values of the corresponding input fields, and the response property will hold the response from the API.

We also have three input elements with x-model attributes that bind their values to the name, email, and message properties. We also have a button element with an x-on:click attribute that listens for a click event and calls a function named submitForm. This function will send the user input to the API and update the response property.

Finally, we have a div element with an x-show attribute that toggles the visibility of the element based on the truthiness of the response property. We also have a span element with an x-text attribute that displays the value of the response property.

<form x-data="{ name: '', email: '', message: '', response: '' }">
  <label for="name">Name:</label>
  <input type="text" id="name" x-model="name">
  <label for="email">Email:</label>
  <input type="email" id="email" x-model="email">
  <label for="message">Message:</label>
  <textarea id="message" x-model="message"></textarea>
  <button x-on:click="submitForm">Submit</button>
  <div x-show="response">
    <span x-text="response"></span>
  </div>
</form>

JavaScript logic

The JavaScript logic of our contact form is written inside the x-data attribute as a plain JavaScript object. We define a method named submitForm that uses the fetch API to make a POST request to the reqres API, which is a fake API for testing purposes. We pass the name, email, and message properties as the body of the request. We then parse the response as JSON and extract the id and createdAt properties from the data. We then assign a success message with the id and createdAt values to the response property, which will automatically update the UI.

<form x-data="{ name: '', email: '', message: '', response: '', submitForm() { fetch('https://reqres.in/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: this.name, email: this.email, message: this.message }) }) .then(response => response.json()) .then(data => { let id = data.id; let createdAt = data.createdAt; this.response = `Your message has been sent with id ${id} at ${createdAt}`; }) .catch(error => console.error(error)); } }">
  <label for="name">Name:</label>
  <input type="text" id="name" x-model="name">
  <label for="email">Email:</label>
  <input type="email" id="email" x-model="email">
  <label for="message">Message:</label>
  <textarea id="message" x-model="message"></textarea>
  <button x-on:click="submitForm">Submit</button>
  <div x-show="response">
    <span x-text="response"></span>
  </div>
</form>

Conclusion

In this post, we have learned how to use Alpine JS to build three simple applications: a weather app, a counter app, and a contact form. We have seen how Alpine JS allows us to add interactivity to our web pages with a declarative syntax and minimal code. Alpine JS is a great framework for creating dynamic and responsive web components without the complexity of other frameworks.

If you want to learn more about Alpine JS, you can check out its documentation and GitHub repository. You can also find more examples and tutorials on Alpine Toolbox.