• bitcoinBitcoin(BTC)$81,474.000.23%
  • ethereumEthereum(ETH)$2,350.91-0.49%
  • tetherTether(USDT)$1.000.00%
  • rippleXRP(XRP)$1.431.37%
  • binancecoinBNB(BNB)$648.913.18%
  • usd-coinUSDC(USDC)$1.00-0.01%
  • solanaSolana(SOL)$89.014.23%
  • tronTRON(TRX)$0.3457850.56%
  • Figure HelocFigure Heloc(FIGR_HELOC)$1.02-0.85%
  • dogecoinDogecoin(DOGE)$0.113212-0.75%
  • whitebitWhiteBIT Coin(WBT)$59.64-0.75%
  • USDSUSDS(USDS)$1.000.00%
  • HyperliquidHyperliquid(HYPE)$43.08-2.83%
  • cardanoCardano(ADA)$0.2661773.14%
  • leo-tokenLEO Token(LEO)$10.350.20%
  • zcashZcash(ZEC)$564.9130.47%
  • bitcoin-cashBitcoin Cash(BCH)$466.612.70%
  • moneroMonero(XMR)$420.394.42%
  • chainlinkChainlink(LINK)$9.993.11%
  • the-open-networkToncoin(TON)$2.3929.36%
  • CantonCanton(CC)$0.147369-0.20%
  • stellarStellar(XLM)$0.1607871.37%
  • MemeCoreMemeCore(M)$3.594.41%
  • USD1USD1(USD1)$1.00-0.04%
  • daiDai(DAI)$1.00-0.06%
  • litecoinLitecoin(LTC)$56.912.31%
  • avalanche-2Avalanche(AVAX)$9.612.45%
  • suiSui(SUI)$0.993.40%
  • hedera-hashgraphHedera(HBAR)$0.0914661.80%
  • Ethena USDeEthena USDe(USDE)$1.000.00%
  • shiba-inuShiba Inu(SHIB)$0.0000061.59%
  • RainRain(RAIN)$0.007360-1.67%
  • paypal-usdPayPal USD(PYUSD)$1.000.01%
  • crypto-com-chainCronos(CRO)$0.0707551.90%
  • Circle USYCCircle USYC(USYC)$1.120.00%
  • BittensorBittensor(TAO)$312.7810.52%
  • tether-goldTether Gold(XAUT)$4,666.382.47%
  • Global DollarGlobal Dollar(USDG)$1.00-0.01%
  • BlackRock USD Institutional Digital Liquidity FundBlackRock USD Institutional Digital Liquidity Fund(BUIDL)$1.000.00%
  • pax-goldPAX Gold(PAXG)$4,667.872.53%
  • mantleMantle(MNT)$0.673.72%
  • polkadotPolkadot(DOT)$1.313.22%
  • uniswapUniswap(UNI)$3.463.12%
  • World Liberty FinancialWorld Liberty Financial(WLFI)$0.0670352.95%
  • nearNEAR Protocol(NEAR)$1.5219.98%
  • Pi NetworkPi Network(PI)$0.182100-0.53%
  • SkySky(SKY)$0.080454-0.38%
  • okbOKB(OKB)$87.241.82%
  • Falcon USDFalcon USD(USDF)$1.000.06%
  • HTX DAOHTX DAO(HTX)$0.0000020.56%
TradePoint.io
  • Main
  • AI & Technology
  • Stock Charts
  • Market & News
  • Business
  • Finance Tips
  • Trade Tube
  • Blog
  • Shop
No Result
View All Result
TradePoint.io
No Result
View All Result

How to Build a Fully Interactive Multi-Page NiceGUI Application with Real-Time Dashboard, CRUD Operations, File Upload, and Async Chat

May 6, 2026
in AI & Technology
Reading Time: 8 mins read
A A
How to Build a Fully Interactive Multi-Page NiceGUI Application with Real-Time Dashboard, CRUD Operations, File Upload, and Async Chat
ShareShareShareShareShare

In this tutorial, we build a fully interactive, multi-page web application using NiceGUI. We start by setting up the environment and designing a reusable layout that includes navigation, theming, and dark mode support. As we move forward, we implement a live dashboard with real-time metrics and charts, demonstrating reactive bindings and timed updates. We then extend the application with a complete CRUD-based todo system, followed by a validated form with dialogs and user feedback mechanisms. We also incorporate file upload functionality with dynamic previews and conclude the feature set with an asynchronous chat interface that simulates real-time interaction. Also, we ensure that the app runs seamlessly in Colab by using background threading and dynamic port allocation.

Copy CodeCopiedUse a different Browser
import sys
import subprocess
subprocess.run([sys.executable, "-m", "pip", "install", "-q", "nicegui"], check=True)


import threading, time, random, asyncio, base64, socket
from datetime import datetime
from nicegui import ui, events




class State:
   def __init__(self):
       self.todos = [
           {"id": 1, "task": "Explore NiceGUI",      "done": True,  "priority": "High"},
           {"id": 2, "task": "Build a dashboard",    "done": False, "priority": "Medium"},
           {"id": 3, "task": "Deploy to production", "done": False, "priority": "Low"},
       ]
       self.next_id = 4
       self.metrics = {"users": 1247, "revenue": 8420, "orders": 53}
       self.series = [random.uniform(20, 80) for _ in range(20)]
       self.messages = [{"role": "assistant",
                         "text": "Hi! Type something and I will echo it back."}]


state = State()




def page_shell(active: str) -> None:
   dark = ui.dark_mode()
   drawer = ui.left_drawer(value=True).classes("bg-grey-2")
   with drawer:
       ui.label("Navigation").classes("text-lg font-bold p-2")
       for label, path, icon in [
           ("Dashboard", "/",       "dashboard"),
           ("Todos",     "/todos",  "check_circle"),
           ("Form",      "/form",   "edit_note"),
           ("Upload",    "/upload", "upload_file"),
           ("Chat",      "/chat",   "chat"),
       ]:
           cls = "w-full" + (" bg-primary text-white" if label == active else "")
           ui.button(label,
                     on_click=lambda p=path: ui.navigate.to(p),
                     icon=icon).classes(cls).props("flat align=left no-caps")


   with ui.header(elevated=True).classes("items-center justify-between bg-primary"):
       with ui.row().classes("items-center"):
           ui.button(on_click=drawer.toggle, icon="menu").props("flat color=white")
           ui.label(" NiceGUI Tutorial").classes("text-xl font-semibold text-white")
       ui.button(icon="dark_mode", on_click=dark.toggle).props("flat color=white")


   with ui.footer().classes("bg-grey-3 text-black justify-center"):
       ui.label("Built with NiceGUI · Tutorial Demo")

We install and import all required libraries, then initialize our application state. We define a central State class to manage todos, metrics, chart data, and chat messages across the app. We also built a reusable layout function that provides navigation, a header, a footer, and dark mode support for all pages.

YOU MAY ALSO LIKE

Great Hardware Held Back By Bad Philosophy

Google AI Releases Multi-Token Prediction (MTP) Drafters for Gemma 4: Delivering Up to 3x Faster Inference Without Quality Loss

Copy CodeCopiedUse a different Browser
@ui.page("/")
def dashboard():
   page_shell("Dashboard")
   with ui.column().classes("w-full p-6 gap-6"):
       ui.label("Live Dashboard").classes("text-3xl font-bold")


       with ui.row().classes("gap-4 flex-wrap"):
           for key, label, color, icon in [
               ("users",   "Users",   "primary",  "group"),
               ("revenue", "Revenue", "positive", "attach_money"),
               ("orders",  "Orders",  "warning",  "shopping_cart"),
           ]:
               with ui.card().classes("w-60"):
                   with ui.row().classes("items-center justify-between w-full"):
                       ui.label(label).classes("text-gray-500")
                       ui.icon(icon, size="md").classes(f"text-{color}")
                   ui.label().classes(f"text-3xl font-bold text-{color}") \
                       .bind_text_from(state.metrics, key, backward=lambda v: f"{v:,}")


       with ui.card().classes("w-full"):
           ui.label("Live stream (updates every second)").classes("text-lg font-semibold")
           chart = ui.echart({
               "tooltip": {"trigger": "axis"},
               "xAxis":   {"type": "category", "data": list(range(len(state.series)))},
               "yAxis":   {"type": "value"},
               "series":  [{"data": list(state.series), "type": "line",
                            "smooth": True, "areaStyle": {}}],
           }).classes("h-64 w-full")


           def tick():
               state.series.append(random.uniform(20, 80))
               state.series.pop(0)
               chart.options["series"][0]["data"] = list(state.series)
               chart.update()
               state.metrics["users"]   += random.randint(-2, 4)
               state.metrics["revenue"] += random.randint(-100, 200)
               state.metrics["orders"]  = max(0, state.metrics["orders"] + random.randint(-1, 3))


           ui.timer(1.0, tick)

We create the dashboard page and structure it with responsive UI components. We bind metric cards directly to the state to enable automatic updates and display real-time values. We also implement a live chart using ECharts and dynamically update both the chart and the metrics using a timer.

Copy CodeCopiedUse a different Browser
@ui.page("/todos")
def todos_page():
   page_shell("Todos")
   with ui.column().classes("w-full p-6 gap-4 max-w-4xl mx-auto"):
       ui.label("Todos").classes("text-3xl font-bold")


       with ui.card().classes("w-full"):
           with ui.row().classes("w-full items-center gap-2"):
               task_input   = ui.input(placeholder="What needs doing?").classes("flex-grow")
               priority_sel = ui.select(["Low", "Medium", "High"], value="Medium").classes("w-36")


               def add_todo():
                   if not task_input.value or not task_input.value.strip():
                       ui.notify("Task cannot be empty", type="warning"); return
                   state.todos.append({
                       "id":       state.next_id,
                       "task":     task_input.value.strip(),
                       "done":     False,
                       "priority": priority_sel.value,
                   })
                   state.next_id += 1
                   task_input.value = ""
                   todo_list.refresh()
                   ui.notify("Added!", type="positive")


               ui.button("Add", icon="add", on_click=add_todo).props("color=primary")
               task_input.on("keydown.enter", add_todo)


       @ui.refreshable
       def todo_list():
           if not state.todos:
               ui.label("Nothing here yet 🎉").classes("text-gray-500"); return
           for todo in state.todos:
               with ui.card().classes("w-full"):
                   with ui.row().classes("w-full items-center gap-3"):
                       ui.checkbox(value=todo["done"],
                                   on_change=lambda e, t=todo: t.update(done=e.value))
                       lbl = ui.label(todo["task"]).classes("flex-grow text-lg")
                       if todo["done"]:
                           lbl.style("text-decoration: line-through; opacity: 0.5")
                       color = {"High": "red", "Medium": "orange", "Low": "green"}[todo["priority"]]
                       ui.badge(todo["priority"], color=color)


                       def make_del(t=todo):
                           def _del():
                               state.todos.remove(t)
                               todo_list.refresh()
                               ui.notify("Removed", type="info")
                           return _del


                       ui.button(icon="delete", on_click=make_del()) \
                           .props("flat color=red round dense")


       todo_list()

We implement a complete CRUD-based todo system with add, update, and delete functionality. We handle user input validation and dynamically refresh the UI using NiceGUI’s refreshable components. We also enhance the UI with checkboxes, badges, and notifications to improve interactivity and feedback.

Copy CodeCopiedUse a different Browser
@ui.page("/form")
def form_page():
   page_shell("Form")
   with ui.column().classes("w-full p-6 max-w-2xl mx-auto gap-4"):
       ui.label("Profile Form").classes("text-3xl font-bold")
       with ui.card().classes("w-full gap-2"):
           name  = ui.input("Name",  validation={"Required":         lambda v: bool(v)})
           email = ui.input("Email", validation={"Must be an email": lambda v: "@" in (v or "")})
           age   = ui.number("Age", value=18, min=0, max=120)
           ui.label("Subscription plan").classes("mt-2 text-gray-600")
           plan  = ui.radio(["Free", "Pro", "Enterprise"], value="Free").props("inline")
           agree = ui.checkbox("I accept the terms")


           async def submit():
               if not (name.value and "@" in (email.value or "") and agree.value):
                   ui.notify("Please fix the form first", type="negative"); return
               with ui.dialog() as d, ui.card():
                   ui.label("Submitted!").classes("text-xl font-bold")
                   ui.label(f"Name:  {name.value}")
                   ui.label(f"Email: {email.value}")
                   ui.label(f"Age:   {age.value}")
                   ui.label(f"Plan:  {plan.value}")
                   ui.button("OK", on_click=d.close).props("color=primary")
               d.open()


           ui.button("Submit", on_click=submit).props("color=primary")




@ui.page("/upload")
def upload_page():
   page_shell("Upload")
   with ui.column().classes("w-full p-6 max-w-3xl mx-auto gap-4"):
       ui.label("File Upload").classes("text-3xl font-bold")
       result = ui.column().classes("w-full")


       def handle_upload(e: events.UploadEventArguments):
           content = e.content.read()
           with result:
               with ui.card().classes("w-full"):
                   ui.label(f"📎 {e.name}").classes("font-semibold")
                   ui.label(f"Size: {len(content):,} bytes · type: {e.type}")
                   if e.type and e.type.startswith("image/"):
                       b64 = base64.b64encode(content).decode()
                       ui.image(f"data:{e.type};base64,{b64}").classes("w-64 rounded")
                   else:
                       try:
                           ui.code(content[:500].decode("utf-8", errors="replace"))
                       except Exception:
                           pass
           ui.notify(f"Uploaded {e.name}", type="positive")


       ui.upload(on_upload=handle_upload, multiple=True, auto_upload=True).classes("w-full")

We build a form with validation rules and handle submission using an asynchronous function. We display user input in a dialog upon successful submission and ensure proper validation before processing. We also implement a file upload feature that supports multiple files and provides image previews and content previews for other file types.

Copy CodeCopiedUse a different Browser
@ui.page("/chat")
def chat_page():
   page_shell("Chat")
   with ui.column().classes("w-full p-6 max-w-3xl mx-auto gap-4"):
       ui.label("Chat (echo bot)").classes("text-3xl font-bold")


       @ui.refreshable
       def chat_log():
           for m in state.messages:
               ui.chat_message(
                   m["text"],
                   name="You" if m["role"] == "user" else "Bot",
                   sent=m["role"] == "user",
                   stamp=datetime.now().strftime("%H:%M"),
               )


       with ui.card().classes("w-full"):
           chat_log()


       async def send():
           text = (entry.value or "").strip()
           if not text:
               return
           state.messages.append({"role": "user", "text": text})
           entry.value = ""
           chat_log.refresh()
           await asyncio.sleep(1)
           reply = f'You said: "{text}" — that is {len(text)} characters!'
           state.messages.append({"role": "assistant", "text": reply})
           chat_log.refresh()


       with ui.row().classes("w-full items-center"):
           entry = ui.input(placeholder="Type a message…") \
               .classes("flex-grow").on("keydown.enter", send)
           ui.button(icon="send", on_click=send).props("color=primary round")




def _free_port() -> int:
   s = socket.socket()
   s.bind(("", 0))
   port = s.getsockname()[1]
   s.close()
   return port


PORT = _free_port()




def _serve():
   ui.run(host="0.0.0.0", port=PORT, reload=False, show=False,
          title="NiceGUI Tutorial", storage_secret="colab-demo")


threading.Thread(target=_serve, daemon=True).start()
time.sleep(4)




try:
   from google.colab import output
   from google.colab.output import eval_js
   output.serve_kernel_port_as_iframe(PORT, height="850")
   print(f"App running on port {PORT}")
   print("Open in a new browser tab:")
   print(eval_js(f"google.colab.kernel.proxyPort({PORT})"))
except ImportError:
   print(f"Not in Colab — open http://localhost:{PORT} in your browser")

We develop an asynchronous chat interface that simulates real-time interaction. We manage chat messages in the shared state and dynamically refresh the chat log after each message. Also, we configure the app to run on a dynamically selected free port in a background thread and expose it within the Colab environment.

In conclusion, we developed a comprehensive understanding of how to build and structure modern web applications using NiceGUI. We brought together multiple advanced concepts such as state management, reactive UI updates, routing, asynchronous workflows, and real-time visualization into a single cohesive system. We also addressed practical challenges, such as running web servers in notebook environments and ensuring component reusability. This end-to-end implementation demonstrates the flexibility and power of NiceGUI and also equips us with the skills to prototype, test, and scale interactive applications efficiently.


Check out the Full Codes with Notebook here. Also, feel free to follow us on Twitter and don’t forget to join our 130k+ ML SubReddit and Subscribe to our Newsletter. Wait! are you on telegram? now you can join us on telegram as well.

Need to partner with us for promoting your GitHub Repo OR Hugging Face Page OR Product Release OR Webinar etc.? Connect with us

The post How to Build a Fully Interactive Multi-Page NiceGUI Application with Real-Time Dashboard, CRUD Operations, File Upload, and Async Chat appeared first on MarkTechPost.

Credit: Source link

ShareTweetSendSharePin

Related Posts

Great Hardware Held Back By Bad Philosophy
AI & Technology

Great Hardware Held Back By Bad Philosophy

May 6, 2026
Google AI Releases Multi-Token Prediction (MTP) Drafters for Gemma 4: Delivering Up to 3x Faster Inference Without Quality Loss
AI & Technology

Google AI Releases Multi-Token Prediction (MTP) Drafters for Gemma 4: Delivering Up to 3x Faster Inference Without Quality Loss

May 6, 2026
Pornhub Is Unblocking UK Users Who Verify Their Age With Apple
AI & Technology

Pornhub Is Unblocking UK Users Who Verify Their Age With Apple

May 6, 2026
When Claude Hallucinates in Court: The Latham & Watkins Incident and What It Means for Attorney Liability
AI & Technology

When Claude Hallucinates in Court: The Latham & Watkins Incident and What It Means for Attorney Liability

May 6, 2026
Next Post
When Claude Hallucinates in Court: The Latham & Watkins Incident and What It Means for Attorney Liability

When Claude Hallucinates in Court: The Latham & Watkins Incident and What It Means for Attorney Liability

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Search

No Result
View All Result
Apple Earnings Just Dropped | Here’s What You Need to Know

Apple Earnings Just Dropped | Here’s What You Need to Know

May 1, 2026
NBC Nightly News Full Episode – April 6

NBC Nightly News Full Episode – April 6

May 1, 2026
A New Jersey state trooper rescues a bear cub from a roadside ditch

A New Jersey state trooper rescues a bear cub from a roadside ditch

May 1, 2026

About

Learn more

Our Services

Legal

Privacy Policy

Terms of Use

Bloggers

Learn more

Article Links

Contact

Advertise

Ask us anything

©2020- TradePoint.io - All rights reserved!

Tradepoint.io, being just a publishing and technology platform, is not a registered broker-dealer or investment adviser. So we do not provide investment advice. Rather, brokerage services are provided to clients of Tradepoint.io by independent SEC-registered broker-dealers and members of FINRA/SIPC. Every form of investing carries some risk and past performance is not a guarantee of future results. “Tradepoint.io“, “Instant Investing” and “My Trading Tools” are registered trademarks of Apperbuild, LLC.

This website is operated by Apperbuild, LLC. We have no link to any brokerage firm and we do not provide investment advice. Every information and resource we provide is solely for the education of our readers. © 2020 Apperbuild, LLC. All rights reserved.

No Result
View All Result
  • Main
  • AI & Technology
  • Stock Charts
  • Market & News
  • Business
  • Finance Tips
  • Trade Tube
  • Blog
  • Shop

© 2023 - TradePoint.io - All Rights Reserved!