| name | pythonista-nicegui |
| description | NiceGUI development best practices for Python web UIs. Use when building UI components, fixing layout issues, or working with NiceGUI/Quasar/Tailwind. Triggers on "nicegui", "quasar", "tailwind", "ui.row", "ui.column", "ui.card", "ui.dialog", "gap", "spacing", "layout", "modal", "component", "styling", "flexbox", "chart", or when creating/editing UI code. |
NiceGUI Development Best Practices
Core Philosophy
Understand the user workflow before building. Same data MUST look the same everywhere. Extract business logic from UI into testable controllers.
Critical Rules - Gap Spacing
NEVER use Tailwind gap-* classes in NiceGUI. ALWAYS use inline styles.
with ui.row().classes("items-center").style("gap: 0.75rem"):
ui.icon("info")
ui.label("Message")
with ui.row().classes("items-center gap-3"):
ui.icon("info")
ui.label("Message")
Gap Conversion Table
| Tailwind | Inline Style | Use Case |
|---|
gap-1 | style("gap: 0.25rem") | Minimal (icon + label) |
gap-2 | style("gap: 0.5rem") | Small (within groups) |
gap-3 | style("gap: 0.75rem") | Medium (between elements) |
gap-4 | style("gap: 1rem") | Large (between sections) |
gap-6 | style("gap: 1.5rem") | Extra large |
Critical Rules - Height Issues
NEVER use height: 100% inside a container with only max-height.
with ui.card().style("max-height: 80vh"):
with ui.scroll_area().style("height: 100%"):
ui.label("Content")
with ui.card().style("height: 80vh"):
with ui.scroll_area().style("height: 100%"):
ui.label("Content")
Critical Rules - Side-by-Side Layouts
Use min-width: 0 on flex children when using charts or wide content.
with ui.row().classes("w-full"):
with ui.column().classes("flex-1"):
ui.highchart(options)
with ui.column().classes("flex-1"):
ui.highchart(options)
with ui.element("div").style("display: flex; width: 100%; gap: 24px"):
with ui.element("div").style("flex: 1; min-width: 0"):
ui.highchart(options)
with ui.element("div").style("flex: 1; min-width: 0"):
ui.highchart(options)
Modal/Dialog Button Docking
Primary action buttons MUST be always visible - dock to bottom.
with ui.dialog() as dialog, ui.card().style(
"height: 85vh; display: flex; flex-direction: column;"
):
with ui.scroll_area().style("flex: 1; overflow-y: auto;"):
with ui.element("div").style(
"position: sticky; bottom: 0; padding: 1rem; "
"border-top: 1px solid var(--border-color);"
):
with ui.row().classes("justify-end").style("gap: 0.5rem"):
ui.button("Cancel", on_click=dialog.close)
ui.button("Save", on_click=save_handler)
Product Thinking - Component Design
Before building UI that displays data:
- Where else does this data type appear?
- Should this be ONE component with modes?
- Can user navigate from reference to source?
class PromptReference:
def __init__(self, prompt, mode: Literal["LIBRARY", "REFERENCE", "PREVIEW"]):
if mode == "LIBRARY":
elif mode == "REFERENCE":
UI Architecture - Extract Controllers
Extract business logic from UI handlers into testable controllers.
class PageController:
async def handle_task_change(self, new_task: str) -> PageUpdate:
data = await self.fetcher.fetch_data(new_task)
return PageUpdate.refresh_all(data)
async def on_task_change(e):
logger.info(f"User selected task: {e.value}")
update = await controller.handle_task_change(e.value)
apply_ui_update(update)
async def on_task_change(e):
overview = await service.get_overview()
if overview.tasks:
selected = overview.tasks[0]
chart.refresh(...)
Safe Quasar/Tailwind Classes
These work correctly - no inline style needed:
- Padding:
q-pa-md, q-pa-lg, q-pa-sm
- Margin:
q-mb-md, q-mt-md
- Width:
w-full, w-1/2, w-auto
- Flexbox:
items-center, justify-between, flex-row
- Colors:
bg-grey-9, text-positive
- Typography:
text-h5, text-body1, font-bold
Requires inline style:
- Gap spacing:
gap-* -> style("gap: Xrem")
Checklists
NiceGUI Styling Checklist
Data Display Component Checklist
UI Architecture Checklist
Reference Files
For detailed patterns:
Related Skills
- For testing UI code, see
/pythonista-testing
- For type safety, see
/pythonista-typing
- For pattern discovery, see
/pythonista-patterning