x-if
The x-if directive does not hide an element — it adds it to the page or removes it completely. While the condition is false, the element is not in the markup at all. This is useful when the content is heavy or cannot exist without data — for example, a block that reads properties of the selected task.
The template tag
x-if goes only on a <template> tag. The browser does not display the contents of a <template>, and Alpine copies them into the page when the condition becomes true:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{ loggedIn: false }">
<button @click="loggedIn = !loggedIn">Log in / out</button>
<template x-if="loggedIn">
<p>Welcome, Anna!</p>
</template>
</div>The button adds the paragraph and removes it. Open the developer tools: while the paragraph is not visible, it is not in the element tree either, only the <template> remains.
When you need x-if
The selected task starts as null. The expression selected.title would then throw an error, and x-if prevents it:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{ selected: null }">
<button @click="selected = { title: 'Buy milk', author: 'Oleg' }">Select a task</button>
<template x-if="selected">
<div>
<h3 x-text="selected.title"></h3>
<p x-text="'Author: ' + selected.author"></p>
</div>
</template>
</div>Before the click nothing is shown and there are no errors. After the click the task card appears. With x-show the card would exist from the start, and Alpine would try to read title from null.
x-if or x-show
x-show | x-if | |
|---|---|---|
| Element in the markup | Always | Only when the condition is true |
| Tag | Any | Only <template> |
x-transition animation | Yes | No |
| Frequent toggling | Fast | The element is recreated every time |
Use x-show for menus, hints and modals. Use x-if for blocks that need data that may be missing.
One root element
A <template> must contain exactly one top-level element. Wrap several elements in a <div>, as in the card example.
Common mistake
Putting x-if directly on a <div>:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{ show: false }">
<div x-if="show">This text is always visible</div>
</div>The text is visible although show is false. The directive only works on a <template> — wrap the content in one.