Centralize State and Layout for Scalable Multi-Page Apps

Define a shared State class to hold app data like todos (initially 3 items with id, task, done, priority), metrics (users:1247, revenue:8420, orders:53), series for charts (20 random values 20-80), and messages. Access it globally across pages for reactivity.

Use page_shell(active) to create reusable layouts: left drawer with buttons for pages (/dashboard, /todos, /form, /upload, /chat) that call ui.navigate.to(path); header with menu toggle, title, dark mode button (ui.dark_mode().toggle); footer. Active nav item gets bg-primary text-white. This ensures consistent navigation and theming without repetition.

Decorate pages with @ui.page('/path') for routing. Bind UI to state with .bind_text_from(state.metrics, 'key', backward=lambda v: f'{v:,}') for auto-updates on metric cards (users/revenue/orders with icons, colors: primary/positive/warning).

Drive Real-Time Updates with Timers and Bindings

For dashboards, use ui.echart with ECharts config: category xAxis (0 to len(series)-1), value yAxis, smooth line series with areaStyle. Update via ui.timer(1.0, tick): append/pop random value (20-80) to series, set chart.options['series'][0]['data'] = list(state.series), call chart.update(). Also increment metrics: users += randint(-2,4), revenue += (-100,200), orders max(0, +(-1,3)). Cards reactively show formatted numbers.

Apply @ui.refreshable to functions like todo_list() or chat_log(): re-run on .refresh() after state changes (add/remove todo, send message). This keeps lists dynamic without full page reloads.

Handle CRUD, Forms, Uploads, and Async Flows Interactively

Todos: Input + select (Low/Medium/High), add on button/Enter if non-empty (notify warning else), append {'id': next_id, task, done=False, priority}, increment next_id (starts at 4), refresh list. List shows checkbox (updates todo'done'), strikethrough label if done, color badge (High:red, Medium:orange, Low:green), delete button (remove from list, notify).

Forms: Inputs with validation (name required, email '@' check), number(18,min0,max120), inline radio(Free/Pro/Enterprise), checkbox. Async submit checks all, shows dialog with values if valid (notify negative else).

Uploads: ui.upload(multiple=True, auto_upload=True), on_upload read e.content, show card with name/size/type; for images, base64 data:{type};base64,{b64} preview (w-64); text: decode:500 in ui.code; notify.

Chat: ui.chat_message(text, name='You/Bot', sent=role=='user', stamp='%H:%M') in refreshable log. Async send: append user msg, clear input, refresh, sleep(1), append echo reply (len(text) chars), refresh. Supports Enter/send button.

Run in Colab with Background Threading and Dynamic Ports

Pick free port: socket.bind(('',0)), get getsockname()[1]. Run ui.run(host='0.0.0.0', port=PORT, reload=False, show=False, title='NiceGUI Tutorial') in daemon thread. Sleep 4s, then output.serve_kernel_port_as_iframe(PORT, height='850') and proxy URL. Fallback: localhost:PORT. Enables notebook prototyping without blocking.