RisalDash RisalDash

Guide · Web UI · ESP32

A real web UI, served by the chip

The web page an ESP32 serves doesn’t have to look like it’s from 2004. The same $3 chip can host a reactive interface — gauges that sweep, charts that stream, controls that respond — with no page reloads and no cloud. Here’s how the modern approach fits in flash, where the RAM actually goes, and the shortcut that skips the whole build.

Web UIWebSocketsSPAESP32RisalDash
A modern ESP32 web dashboard: reactive gauges and a live sparkline in a browser, pushed over a WebSocket
Gauges and a live chart, served from flash and updated over a WebSocket — no reloads, no cloud.

Why the old string-built HTML page is a dead end

The classic ESP sketch builds a page by gluing HTML into a giant String and returning it on every request. It works for one gauge and falls apart after that: no reactivity (every change means a full page reload), no components, and the markup lives as unreadable string soup in your firmware. The moment you want a second chart or a control that talks back, you’ve outgrown it.

Build a real SPA — then pack it into flash

The modern move is to build the front end like any web app — Vue, Svelte, React, or just modern vanilla — with a bundler (Vite) that outputs a tiny, minified index.html plus JS/CSS. You then drop those files into the ESP’s flash filesystem (LittleFS or SPIFFS) and serve them as static assets. The chip isn’t running a framework; it’s just handing over pre-built files — so a Svelte app and a plain one cost the ESP the same.

Live data over a WebSocket, not polling

Reactivity comes from the transport. Instead of the browser asking “any news?” on a timer, open a WebSocket (via ESPAsyncWebServer) and let the device push the moment a value changes:

loop():   read sensor   →   ws push {temp: 24.1}     // send, don't be polled
browser:  ws.onmessage  →   gauge.value = 24.1        // update in place, no reload

One socket carries every widget’s data as small JSON frames; the page mutates in place. That’s what makes a served dashboard feel like an app instead of a document — and it’s exactly how the agent face reacts live, too.

Watch the RAM — serve from flash, gzip, stream

The trap is holding big things in RAM. A bundled SPA can be tens of kilobytes — don’t read it into a String. Store the assets gzipped in flash and stream them with a Content-Encoding: gzip header, so both the storage and the transfer are small. Keep large constant blobs in PROGMEM, send in chunks, and free buffers early — see how ESP32 memory works. Done right, a rich UI barely dents the heap.

Or don’t hand-roll any of it

All of the above — the bundler, the filesystem upload, the WebSocket protocol, the RAM discipline — is real work you can skip. RisalDash generates the whole front end (HTML, CSS, JS and the WebSocket wiring) from a few lines of C++: you describe widgets, bind variables, and the reactive dashboard is served for you. Its Zero-Waste UI even strips the widgets you don’t use, so you pay only for what’s on screen.

The 30-second decision

ApproachEffortReactive?Best for
HTML in a Stringtinyno (reloads)one value, a toy
Hand-built SPA + LittleFShighyes (WebSocket)full control, custom design
RisalDasha few linesyes (built in)a real dashboard, fast

Rule of thumb: a single readout → a string page is fine; a bespoke product UI → build the SPA and own it; a real dashboard without the plumbing → let it be generated.

See a reactive dashboard — gauges, charts, controls, a live map — served from a chip.