ESC
Type to search...
S
Soli Docs

Live View

Build reactive, real-time interfaces without writing JavaScript. Live View renders components on the server and efficiently updates the DOM over WebSockets.

See it in action

Try the interactive counter demo on our landing page.

Try Live Demo

How It Works

Live View is a server-rendered component system that maintains state on the server. When users interact with the page, events are sent over WebSockets, the server updates the component state, re-renders the template, and sends back only the differences (diffs) to update the DOM.

User Event
Click, Submit, Change
Server
Update State & Render
DOM Update
Apply Diff Patch

Creating a Live View Component

Step 1: Create the Template

Create a .sliv file in app/views/live/. Use @variable syntax for reactive state.

<div class="counter-component">
    <h2>Count: @count</h2>

    <button soli-click="decrement">-</button>
    <button soli-click="increment">+</button>
</div>

Step 2: Register the Route

Register your Live View component in config/routes.sl using the router_live function.

# Register LiveView components
router_live("counter", "live#counter");
router_live("metrics", "live#metrics");

Step 3: Create the Controller

Create a controller that handles events. The handler receives an event hash with event (name), params, and state. Return the new state as a hash.

# Counter component handler
def counter(event_data: Any)    let event = event_data["event"];   # Event name (e.g., "increment")
    let params = event_data["params"]; # Event parameters
    let state = event_data["state"];   # Current component state
    let count = state["count"];

    if (count == null)
        count = 0;
    end

    if (event == "increment")
        return { "count": count + 1 };
    end

    if (event == "decrement")
        return { "count": count - 1 };
    end

    # Return unchanged state for unknown events
    state
end

Available Directives

soli-click

Triggers on element click. <button soli-click="save">

soli-submit

Triggers on form submission. <form soli-submit="create">

soli-change

Triggers on input value change. <select soli-change="filter">

soli-keydown

Triggers on key press. <input soli-keydown="search">

soli-keyup

Triggers on key release. <input soli-keyup="validate">

soli-focus

Triggers when element gains focus. <input soli-focus="highlight">

soli-blur

Triggers when element loses focus. <input soli-blur="validate">

soli-value-*

Binds input value to state. <input soli-value-name>

soli-target

Specifies target component for updates. <div soli-target="results">

soli-debounce

Debounces event by ms. <input soli-keyup="search" soli-debounce="300">

State Management

State is stored on the server and accessed in templates using @variable syntax. The server maintains state between events.

<!-- Simple variable -->
<span>Hello, @username</span>

<!-- Conditional rendering -->
<% if @logged_in %>
    <a href="/logout">Sign Out</a>
<% else %>
    <a href="/login">Sign In</a>
<% end %>

<!-- Iteration -->
<% for item in @items %>
    <li><%= item["name"] %></li>
<% end %>

Client Setup

Include the Live View client library and mount your component.

<!-- Include the Live View client (~2KB gzipped) -->
<script src="/js/live.js"></script>

<!-- Mount a Live View component -->
<div id="counter" data-live-view="counter"></div>

<script>
    # Initialize Live View
    SoliLive.connect();
</script>

Route Configuration

Register the Live View WebSocket endpoint in your routes.

# Live View WebSocket endpoint
router_live("/live/counter", "live#counter");

High-Rate Updates

Live View supports server-pushed updates for real-time dashboards, monitoring, and live data feeds. Use the tick event type to push updates at high frequencies (up to 60 updates/second).

def metrics_dashboard(event: Any)    let type = event["type"];

    if (type == "connect")
        # Set tick interval in milliseconds (50ms = 20 updates/sec)
        return {
            "state": { "cpu": 0, "memory": 0, "requests": 0 },
            "tick_interval": 50
        };
    end

    if (type == "tick")
        # Server pushes fresh data on each tick
        return {
            "state": {
                "time": datetime_now(),
                "cpu": system_cpu_usage(),
                "memory": system_memory_mb(),
                "requests": request_counter()
            }
        };
    end

    {}
end
<div class="dashboard">
    <div class="metric">
        <span class="label">Server Time</span>
        <span class="value">@time</span>
    </div>
    <div class="metric">
        <span class="label">CPU</span>
        <span class="value">@cpu%</span>
    </div>
    <div class="metric">
        <span class="label">Memory</span>
        <span class="value">@memory MB</span>
    </div>
    <div class="metric">
        <span class="label">Requests/sec</span>
        <span class="value">@requests</span>
    </div>
</div>

Tick Intervals

  • 1000ms - Good for dashboards, status pages
  • 100ms - Good for live charts, activity feeds
  • 50ms (20/s) - Good for real-time monitoring
  • 16ms (60/s) - Maximum rate, use sparingly for animations

Performance

~2KB
Client Size (gzipped)
<50ms
Round-trip Latency
Diff
Minimal Updates

Why Live View?

  • No JavaScript required - Build interactive UIs with just server-side code
  • SEO friendly - Initial HTML is server-rendered
  • Reduced complexity - No client-side state management to maintain
  • Real-time by default - WebSocket connection enables instant updates