Directives

Directives are special attributes that extend HTML with reactive logic. They allow you to manipulate the DOM structure and behavior without leaving your template.

Conditional Rendering

PawaJS uses if, else-if, and else to conditionally include or remove elements from the DOM.

html

                 
<div if="isLoggedIn.value">Welcome back!</div>
<div else-if="isGuest.value">Welcome, Guest</div>
<div else="">Please sign in</div> 

        

Inline State (state-*)

The state-* directive allows you to declare reactive state directly on any HTML element. The state is automatically exposed to the element and its children.

The value assigned to state-* is evaluated as a JavaScript expression, so you can define numbers, strings, booleans, objects, or arrays.

html

                 
<!-- Number state: state-count="0" -->
<div state-count="0" class="p-4 border rounded-md bg-muted/20">
    <p>Current Count: @{count.value}</p>
    <button on-click="count.value++" class="mt-2 px-3 py-1 bg-blue-500 text-white rounded">Increment</button>
</div>

<!-- String state: state-message="'Hello PawaJS'" -->
<div state-message="'Hello PawaJS'" class="p-4 border rounded-md bg-muted/20">
    <input type="text" @value="@{message.value}" on-input="message.value = e.target.value" class="border rounded px-2 py-1 w-full">
    <p class="mt-2">Message: @{message.value}</p>
</div>

<!-- Object state: state-user="{name: 'John Doe', age: 30}" -->
<div state-user="{name: 'John Doe', age: 30}" class="p-4 border rounded-md bg-muted/20">
    <p>User Name: @{user.value.name}</p>
    <p>User Age: @{user.value.age}</p>
    <button on-click="user.value.age++" class="mt-2 px-3 py-1 bg-purple-500 text-white rounded">Increase Age</button>
</div>

<!-- Boolean state: state-isactive="true" -->
<div state-isactive="true" class="p-4 border rounded-md bg-muted/20">
    <button on-click="isactive.value = !isactive.value" class="px-3 py-1 rounded @{isactive.value ? 'bg-green-500' : 'bg-red-500'} text-white">
        Status: @{isactive.value ? 'Active' : 'Inactive'}
    </button>
</div>

<!-- Array state: state-items="['Apple', 'Banana', 'Cherry']" -->
<ul state-items="['Apple', 'Banana', 'Cherry']" class="p-4 border rounded-md bg-muted/20 list-disc pl-5">
    <li for-each="item in items.value" for-key="{{item}}">
        @{item}
    </li>
</ul> 

        

List Rendering (Looping)

The for-each directive iterates over an array. For optimal performance during updates, always provide a for-key.

html

                 
<ul>
    <!-- Syntax: item, index in array -->
    <li for-each="user, i in users.value" for-key="{{user.id}}">
        @{i}: @{user.name}
    </li>
</ul> 

        
Note: for-key uses double braces {{ }} to evaluate the key in the loop context.

Switch Directives

Cleanly handle multiple conditions using switch, case, and default.

html

                 
<span switch="status.value" case="'loading'">Loading...</span>
    <span case="'success'">Data retrieved!</span>
    <span s-default="">Something went wrong</span> 

        

Event Handling

Events are wired using on-[event]. Use out-[event] to capture interactions outside the element.

Standard (on-)

html

                 
<button on-click="save()">Save</button>
<!-- Modifiers: prevent, debounce, once -->
<input on-input.debounce.500="search()"> 

        

Outside (out-)

html

                 
<!-- Perfect for closing dropdowns/modals -->
<div class="dropdown" out-click="isOpen.value = false">
    Menu Content
</div> 

        

The ref Directive

The ref directive provides a way to access a DOM element or component instance directly. It's useful for integrating with third-party libraries that require direct DOM manipulation, or for imperative interactions.

html

                 
<!-- Assigns the input element to myInput.value in your component's context -->
<input ref="myInput" type="text" placeholder="Focus me!">

<!-- You can then access it in your JavaScript: myInput.value.focus() --> 

        

Lifecycle Directives

Tap into the creation and destruction of elements directly from your HTML. These are perfect for initializing third-party libraries or cleaning up resources.

mount

Executes when the element is inserted into the DOM.

html

                 
<div mount="console.log('Element is live!')">...</div> 

        

unmount

Executes just before the element is removed from the DOM.

html

                 
<div unmount="cleanupResources()">...</div> 

        

The key Directive

The key directive forces a component or element to fully re-render (destroy and recreate) when the keyed value changes.

html

                 
<!-- Re-renders the profile view when the ID changes -->
<user-profile key="currentUserId.value"></user-profile> 

        

Timer Directives

Handle time-based logic directly in HTML without setting manual intervals or timeouts in JavaScript.

after-[duration]

Executes the expression once after the delay.

html

                 
<div after-[5s]="notification.value = false">
    This alert will hide in 5 seconds.
</div> 

        

every-[duration]

Executes the expression repeatedly at the specified interval.

html

                 
<div every-[1s]="seconds.value++">
    Time elapsed: @{seconds.value}s
</div> 

        

Rendering Control (Avoid)

Sometimes you need PawaJS to ignore specific parts of your DOM. These directives prevent the engine from processing an element and its children.

pawa-avoid

Prevents client-side PawaJS from reactive tracking and rendering of this element tree. Useful for static islands or third-party DOM containers.

html

                 
<div pawa-avoid="">
    <!-- PawaJS engine ignores everything here -->
    <div id="d3-chart-container"></div>
</div> 

        

s-pawa-avoid

Prevents server-side (SSR) rendering of the element. The element will only be processed on the client.

html

                 
<div s-pawa-avoid="">
    <!-- This won't appear in the initial server HTML -->
</div> 

        

only-client

Prevents an element or component from being rendered on the server. During SSR, PawaJS renders a placeholder template, allowing the client-side runtime to take over execution.

html

                 
<heavy-widget only-client=""></heavy-widget>