NiceGUI notes
NiceGUI is freaking awesome.
-
Resources
- NiceGUI Documentation that leads to nicegui/examples at main · zauberzeug/nicegui and is the most useful examples I’ve seen in any python project ever.
- There’s a FAQs · zauberzeug/nicegui Wiki that I found far too late
- Has bits about performance, long-running functions etc.
-
Useful examples
- search_as_you_type for updating a table based on
Misc
- ui.list | NiceGUI hows very pretty complex lists with sections!
- ui.icon | NiceGUI works for icons: Material Symbols & Icons - Google Fonts
- Tooltips can contain all other elements! ui.tooltip | NiceGUI
- All inputs, labels date etc: Input | Quasar Framework
- ui.radio | NiceGUI
props('inline')for inline, remove for vertical;denseexists - ui.number | NiceGUI makes binding and processing string ui.inputs easier!
Modularization
- Modularization example: nicegui/examples/modularization at main · zauberzeug/nicegui
- apirouter
- fn, class, etc.
# somewhere
def create() -> None:
@ui.page('/a')
def page_a():
with theme.frame('- Page A -'):
message('Page A')
ui.label('This page is defined in a function.')
from somewhere import create
# Example 2: use a function to move the whole page creation into a separate file
# in main.py
function_example.create()
Slots
OK I think I got it! In e.g. Select | Quasar Framework look for “slots” then you can use them thus1:
sel = ui.select(
list(items),
value=item,
)
with sel.add_slot("after"):
ui.button(icon="description").props("flat no-caps").on(
"click",
lambda e: ui.navigate.to(f"/bp/{whatever}"),
)
Table magic
table = ui.table()#...
with table.add_slot("body-cell-ColumnName"):
with table.cell("ColumnName"):
# button w/ cell text
ui.button().props("""
:innerHTML="props.value"
""").on(
"click",
js_handler="() => emit(props.row.SomeColumnName)",
handler=lambda e: ui.navigate.to(f"/sth/{e.args}"), # e.args is cell content
)
# conditionals
.props(""" flat no-caps
:label="props.value !== 'N/A' ? props.value : ''"
""")
Link
… with button
with ui.link(target="/sd"):
ui.button("Show", icon="description")
… without underline
with ui.link(target=target_link).classes("no-underline"):
ui.item_label("look ma no underline!")
Multiple badges
Ref: Badge: Floating - Quasar Playground but that’s quasar-heavy. Strangely not mentioned in the official quasar docs either. After playing with this this is the python solution:
# remove the floating prop and add one of these classes.
# Removing the prop is useful if using e.g. both top-left and top-right
# then they are on an identicafl height
ui.badge(faiss_dist_str, color="light-blue-10").props(
# "floating"
).classes("absolute-top-left")
Styling
- Quasar header classes: Typography | Quasar Framework
Events
ui.table(rows=rows).props("flat bordered").on(
"row-click",
lambda e: ui.navigate.to(f"/pr/{e.args[1]['ISIN']}"),
)
The row-click event comes from quasar: https://quasar.dev/vue-components/table#qtable-api
APIs
-
ui.run(..., fastapi_docs=True)to make documentation available -
nicegui/examples/api_requests/main.py at main · zauberzeug/nicegui
async def show_new_quote():
async with httpx.AsyncClient() as client:
response = await client.get('https://zenquotes.io/api/quotes')
quote = random.choice(response.json())['q']
label.text = f'“{quote}”'
Snippets
Debugging long-running functions
From the FAQ:
# (..) app.on_startup(setup)
# def setup():
# if CFG.debug_mode:
import asyncio
loop = asyncio.get_running_loop()
loop.set_debug(True)
loop.slow_callback_duration = 0.05
Uploading files
ui.upload(
auto_upload=True, on_upload=lambda e: handle_upload(e)
).classes("max-w-full")
async def handle_upload(e: events.UploadEventArguments):
with tempfile.NamedTemporaryFile(delete=False, prefix="uns") as tmp:
save_path = Path(tmp.name)
await e.file.save(save_path)
return save_path
Bonus: FastAPI File upload
- python - How to Upload File using FastAPI? - Stack Overflow has many diff ways
- Building a Secure and Efficient File Upload API in FastAPI | Mahdi Abu Tafish is a deep dive
- blocking operations, security, etc.
TODO
Focus
element.run_method('focus')
focuses the element, I could connect this to ui.keyboard | NiceGUI to do nice keyboard-centric focus of important fields!
Ref: element.run_method(‘focus’) not working · Issue #1092 · zauberzeug/nicegui (not documented elsewhere I could find)
Elsewhere
Validating in real time based on a pydantic BaseModel!: Real-Time Form Validation in Python Using Pydantic | by Aman Deep | Medium
Async hell
Using a variable globally defined outside a function creates issues. E.g. globally WHAT=‘ever’ and then inside a function. TODO better description.