Dynamic Attributes & Classes
Wunderframe provides a flexible and powerful system for manipulating HTML attributes and CSS classes dynamically. This allows you to build responsive, stateful components with ease, from simple dynamic properties to complex conditional styling.
Attribute Binding
You can bind attributes to dynamic values using the same curly brace syntax as text interpolation.
<script>
local imageUrl = "/images/profile.png"
local altText = "A portrait of the user"
local isDisabled = false
</script>
<img src={imageUrl} alt={altText} />
<button disabled={isDisabled}>Submit</button>
Boolean Attributes
For boolean attributes like disabled
, checked
, or selected
, you can use a shorthand. If the variable is true
, the attribute is included; if false
, it's omitted.
<input type="checkbox" checked={isSubscribed} />
<!-- Shorthand: equivalent to checked={checked} -->
<input type="checkbox" {checked} />
Dynamic CSS Classes
Managing CSS classes is a common task, and Wunderframe offers a special syntax to make it declarative and intuitive, inspired by modern frameworks.
Conditional Classes with Tables
The most powerful way to handle classes is by passing a Lua table to the class
attribute. The keys are the class names, and the boolean values determine if they are included in the rendered HTML.
This makes it easy to mix static and dynamic classes, and to toggle classes based on component state.
<script>
local hasError = true
local isPrimary = false
</script>
<div class={{
["button"]: true, -- always include 'button'
["button-primary"]: isPrimary,
["button-error"]: hasError,
["font-bold text-lg"]: true -- multiple classes in one key
}}>
Click Me
</div>
Result:
<div class="button button-error font-bold text-lg">
Click Me
</div>
You can also define this table in a <script>
block for cleaner templates, especially with complex logic.
<script>
local classes = {
["text-blue-200 bg-red-100"]: true,
["font-bold"]: false
}
</script>
<div class={classes}>
Styled content
</div>
Result:
<div class="text-blue-200 bg-red-100">
Styled content
</div>
Integrating with Client-Side Libraries
When working with client-side libraries like Alpine.js or htmx, you often need to pass data in attributes like x-data
or hx-vals
.
If the data is complex (e.g., a JSON object), you can construct it as a string in your <script>
block and inject it as raw HTML using the {@html}
tag.
Here’s an example of setting up an Alpine.js component:
<script>
-- Note: In a real app, you would use a JSON library
-- to safely construct this string.
local xdata = [[
{
mobileMenuOpen: false,
userDropdownOpen: false,
darkMode: localStorage.getItem('darkMode') === 'true' || false
}
]]
</script>
<div x-data={@html xdata}>
<!-- Your Alpine component markup -->
<button @click="darkMode = !darkMode">Toggle Dark Mode</button>
</div>
This technique gives you the full power of server-side rendering combined with rich client-side interactivity.