RizzyUI

Alpine.js Fundamentals for RizzyUI Developers

Before we dive into more advanced patterns, let’s get comfortable with the core building blocks of Alpine.js. These are the features you’ll use every time you add interactivity to a RizzyUI component.

We’ll start with the essentials—defining state, responding to events, updating the DOM—and show how each one fits naturally into the RizzyUI ecosystem. By the end of this page, you’ll have the foundation you need to make your Blazor components feel responsive and alive.

x-data: The Heart of Your Component

At the heart of every interactive component is its state—the data it needs to remember, like whether a dropdown is open or what a user has typed into a search box. In Alpine, you define this state using the x-data directive.

Source
<div x-data="{ open: false, searchTerm: '' }">
  <!-- This div and all its children can now access 'open' and 'searchTerm' -->
</div>

How It Works: The x-data directive creates a reactive "scope." Any element inside this <div> can read and modify the open and searchTerm properties. When they change, Alpine automatically updates any part of the UI that depends on them.

x-on: Responding to Events

Now that we have state, how do we change it? With browser events. Alpine uses the x-on directive to listen for events like clicks, input, and mouse movements.

Here’s how you’d use it with an <RzButton>:

HTML
<div x-data="{ count: 0, increment() { this.count++ } }">
  <RzButton x-on:click="increment">Increment</RzButton>
  <span>Count: <span x-text="count"></span></span>
</div>

How It Works: When the <RzButton> is clicked, the increment method inside our x-data object is called. This is the fundamental pattern for making your components interactive.

Interacting with the DOM

Your Alpine component will often need to read from or write to the HTML. Alpine provides simple, declarative directives for this.

  • x-text: Safely updates the text content of an element. It's like Blazor's @myVariable.
  • x-html: Renders raw HTML. Use this with caution and only with trusted content.
  • x-ref: Gives you a "handle" to a specific element so you can access it directly from your JavaScript methods.

The Reactive Way (Recommended)

The best way to update the DOM is to change your state and let Alpine handle the rest using reactive directives.

Source
<div x-data="{ message: 'Hello!' }">
  <p>The message is: <strong x-text="message"></strong></p>
  <RzButton x-on:click="message = 'Updated!'">Update It</RzButton>
</div>

Direct DOM Access with $refs (Advanced)

For special cases, like integrating with a third-party library or measuring an element's size, you can get a direct handle to a DOM node using x-ref.

Source
<div x-data="{ updateMessage() { this.$refs.output.innerText = 'Updated Directly!' } }">
  <p>The message is: <strong x-ref="output">Hello!</strong></p>
  <RzButton x-on:click="updateMessage">Update via $refs</RzButton>
</div>

Conditional Logic & Styling with x-show and :class

A huge part of interactivity is showing, hiding, or changing the appearance of elements based on state. Alpine provides two powerful directives for this.

Source
<div x-data="{ isSaved: false, save() { this.isSaved = true; setTimeout(() => this.isSaved = false, 2000) } }">

  <RzButton
    x-on:click="save"
    :aria-busy="isSaved ? 'true' : 'false'"
    Variant="ThemeVariant.Primary"
    class="transition-colors"
    :class="{ 'bg-success hover:bg-success/90': isSaved }">
    <span x-show="!isSaved">Save</span>
    <span x-show="isSaved" x-cloak>Saved!</span>
  </RzButton>

  <RzAlert x-show="isSaved" x-transition Variant="ThemeVariant.Success" class="mt-4" role="status" aria-live="polite">
    <AlertTitle>Success!</AlertTitle>
    <AlertDescription>Your changes have been saved.</AlertDescription>
  </RzAlert>

</div>

The Standard vs. CSP Build

RizzyUI provides two client-side scripts, and your choice affects how you write Alpine code.

BuildUsage
rizzyui.js (Standard)Flexible and allows simple inline JavaScript expressions like x-on:click="count++". Perfect for rapid development and projects without strict security requirements.
rizzyui-csp.js (CSP-Compliant)For applications requiring a strict Content Security Policy. This build disables inline script evaluation, so all logic must be in methods (e.g., x-on:click="increment") defined in co-located .razor.js files.

Our recommendation: Even if you don't need CSP, moving logic into methods and co-located files is a best practice. If an inline expression gets longer than a few words or is reused, it's a good sign that it belongs in a method.

Next Steps

Now that you've seen the fundamental directives, you're ready to learn the official RizzyUI pattern for organizing this logic. On the next page, we'll create our first Alpine code-behind with `RzAlpineComponent`.