Build Web Tools with Python Only: Introducing NiceGUI

This article introduces NiceGUI, a pure‑Python web UI framework that lets developers create fully functional, visually appealing web applications without writing any HTML, CSS, or JavaScript, covering its core concepts, quick‑start example, advanced features, component library, layout system, data‑visualisation integration, multi‑page support, suitable scenarios, and a comparison with traditional web development.

Data Party THU
Data Party THU
Data Party THU
Build Web Tools with Python Only: Introducing NiceGUI

NiceGUI: a Python‑only Web UI framework

NiceGUI lets Python developers create fully functional, aesthetically pleasing web applications without writing any HTML, CSS or JavaScript. It wraps the Vue.js/Quasar stack and generates the required front‑end code automatically.

Why use NiceGUI?

Low learning cost : if you know Python, almost zero extra learning.

Fast development : ideas become interactive pages in minutes.

No environment setup : no Node.js, Webpack or other front‑end toolchains required.

Prototype‑to‑product : prototypes can be deployed directly as production apps.

5‑minute starter: a temperature converter

Environment

Python 3.7+ and a single command:

# Install NiceGUI
pip install nicegui

Code

Create temperature_converter.py with the following content:

from nicegui import ui

def celsius_to_fahrenheit(celsius: float) -> float:
    """Convert °C to °F"""
    return (celsius * 9 / 5) + 32

def fahrenheit_to_celsius(fahrenheit: float) -> float:
    """Convert °F to °C"""
    return (fahrenheit - 32) * 5 / 9

ui.label('🌡️ Temperature Converter').classes('text-2xl font-bold text-blue-600')

with ui.row().classes('w-full gap-4'):
    celsius_input = ui.input(label='Celsius (°C)', placeholder='Enter value',
                             validation={'Enter a number': lambda v: v == '' or v.replace('.', '', 1).isdigit()}
                            ).classes('w-48')
    fahrenheit_input = ui.input(label='Fahrenheit (°F)', placeholder='Enter value',
                               validation={'Enter a number': lambda v: v == '' or v.replace('.', '', 1).isdigit()}
                              ).classes('w-48')

def update_fahrenheit():
    """Update Fahrenheit when Celsius changes"""
    try:
        c = float(celsius_input.value) if celsius_input.value else 0
        fahrenheit_input.value = f'{celsius_to_fahrenheit(c):.2f}'
    except ValueError:
        fahrenheit_input.value = ''

def update_celsius():
    """Update Celsius when Fahrenheit changes"""
    try:
        f = float(fahrenheit_input.value) if fahrenheit_input.value else 0
        celsius_input.value = f'{fahrenheit_to_celsius(f):.2f}'
    except ValueError:
        celsius_input.value = ''

celsius_input.on('update:model-value', lambda e: update_fahrenheit())
fahrenheit_input.on('update:model-value', lambda e: update_celsius())

with ui.card().classes('mt-4 w-full'):
    ui.label('💡 Usage').classes('text-lg font-semibold')
    ui.label('• Type a temperature in either box')
    ui.label('• The other box updates automatically')
    ui.label('• Supports decimal input, rounded to two places')

ui.run(title='Temperature Converter', favicon='🌡️', reload=True)

Run the script with python temperature_converter.py and open http://localhost:8080 to see the live converter.

Advanced example: real‑time character counter

The following script demonstrates data binding, dynamic styling, and notifications.

from nicegui import ui
from datetime import datetime

ui.label('📝 Real‑time Text Analyzer').classes('text-2xl font-bold text-purple-600')
text_area = ui.textarea(label='Enter text', placeholder='Start typing...', on_change=lambda e: None).classes('w-full h-40')

with ui.row().classes('w-full gap-4 mt-4'):
    char_card = ui.card().classes('flex-1')
    with char_card:
        ui.label('Characters').classes('text-sm text-gray-500')
        char_count = ui.label('0').classes('text-3xl font-bold text-green-600')
    word_card = ui.card().classes('flex-1')
    with word_card:
        ui.label('Words').classes('text-sm text-gray-500')
        word_count = ui.label('0').classes('text-3xl font-bold text-blue-600')
    line_card = ui.card().classes('flex-1')
    with line_card:
        ui.label('Lines').classes('text-sm text-gray-500')
        line_count = ui.label('0').classes('text-3xl font-bold text-red-600')

update_time = ui.label('Last update: never').classes('text-sm text-gray-400 mt-2')

def analyze_text(e):
    txt = e.args if e.args else ''
    chars = len(txt)
    words = len(txt.split()) if txt.strip() else 0
    lines = txt.count('
') + (1 if txt else 0)
    char_count.set_text(str(chars))
    word_count.set_text(str(words))
    line_count.set_text(str(lines))
    update_time.set_text(f'Last update: {datetime.now().strftime("%H:%M:%S")}')
    if chars > 200:
        char_count.classes(replace='text-3xl font-bold text-red-600')
        ui.notify('Text is long, consider splitting.', type='warning')
    elif chars > 100:
        char_count.classes(replace='text-3xl font-bold text-yellow-600')
    else:
        char_count.classes(replace='text-3xl font-bold text-green-600')

text_area.on('update:model-value', analyze_text)

def reset_text():
    text_area.value = ''
    analyze_text(type('Event', (), {'args': ''})())

ui.button('Clear text', on_click=reset_text, icon='delete').classes('mt-4')
ui.run(title='Text Analyzer', port=8081)

Core advantages and practical tips

Rich built‑in components

NiceGUI provides ready‑made widgets such as ui.button, ui.checkbox, ui.select, ui.slider, ui.toggle, and ui.upload.

Powerful layout system

Vertical columns, horizontal rows, and grid layouts can be created with ui.column(), ui.row(), and ui.grid(), allowing flexible UI composition.

Data‑visualisation integration

Matplotlib figures can be embedded directly via ui.pyplot(fig).

Multi‑page applications

Define pages with the @ui.page('/') decorator and navigate between them using ui.open().

Suitable scenarios

Internal tools – data query interfaces, report generators, configuration panels.

Rapid prototyping – validate product ideas before investing in front‑end development.

Data‑science dashboards – showcase machine‑learning models and analytics.

IoT control panels – smart‑home or device monitoring interfaces.

Education and demos – algorithm visualisation and interactive teaching aids.

When a traditional stack may be preferable

Complex consumer‑facing applications requiring sophisticated front‑end interactions.

Public websites with strict SEO requirements.

Projects that need a deeply customised UI design system.

NiceGUI vs traditional web development

Implementing the same functionality with raw HTML/CSS/JS typically involves setting up a Node.js toolchain, writing separate front‑end code, and handling client‑server integration manually. NiceGUI abstracts all of that, letting developers focus on business logic.

Conclusion

NiceGUI dramatically lowers the barrier to web development for Python developers, enabling rapid creation of internal tools, prototypes, and small‑to‑medium web applications. It exemplifies a broader trend toward letting developers concentrate on core logic while the framework handles repetitive front‑end boilerplate.

NiceGUI overview
NiceGUI overview
NiceGUI screenshot
NiceGUI screenshot
Traditional vs NiceGUI comparison
Traditional vs NiceGUI comparison
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PythonRapid PrototypingWeb UINiceGUINo-code Frontend
Data Party THU
Written by

Data Party THU

Official platform of Tsinghua Big Data Research Center, sharing the team's latest research, teaching updates, and big data news.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.