home / skills / gigaverse-app / skillet / pythonista-nicegui

pythonista-nicegui skill

/pythonista/skills/pythonista-nicegui

This skill helps you build consistent NiceGUI interfaces by enforcing controller-first design, inline styling, and reusable components for reliable UI behavior.

npx playbooks add skill gigaverse-app/skillet --skill pythonista-nicegui

Review the files below or copy the command above to add this skill to your agents.

Files (4)
SKILL.md
4.6 KB
---
name: pythonista-nicegui
description: Use when building UI with NiceGUI, creating components, fixing styling issues. 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.**

## Key Points From References

1. **No threads for UI** - Only use asyncio (see ui-architecture.md)
2. **Three-layer architecture**: Data fetching → Controller → UI (see ui-architecture.md)
3. **Progressive complexity**: Simple pages → Controllers → State machines (see ui-architecture.md)

## Quick Start

```bash
# In Claude Code, use Grep tool:
# pattern="ui.card" path="src/"
# pattern="ui.dialog" path="src/"

# Check for existing components
ls src/*/ui/components/
```

## Critical Styling Rules

```python
# ALWAYS use inline style for gap (NiceGUI bug #2171)
with ui.row().classes("items-center").style("gap: 0.75rem"):
    ui.icon("info")
    ui.label("Message")

# NEVER use Tailwind gap-* classes - breaks on Ubuntu!
# Gap conversion: gap-2->0.5rem, gap-3->0.75rem, gap-4->1rem

# CORRECT: Explicit height for percentage children
with ui.card().style("height: 80vh"):
    with ui.scroll_area().style("height: 100%"):
        ui.label("Content")

# NEVER use height: 100% inside max-height container (collapses to 0!)

# Side-by-side with charts: use min-width: 0
with ui.element("div").style("display: flex; width: 100%; gap: 24px"):
    with ui.element("div").style("flex: 1; min-width: 0"):
        ui.highchart(options)
```

## Controller Pattern

```python
# Extract business logic to controller
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)

# UI layer is thin - delegates to controller
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)

# NEVER put business logic in UI handlers
```

## Component Reuse

```python
# BEFORE building any data display, answer:
# 1. Where else does this data type appear?
# 2. Should this be ONE component with modes?
# 3. Can user navigate from reference to source?

# Create reusable component with modes
class ItemReference:
    def __init__(self, item, mode: Literal["LIBRARY", "REFERENCE", "PREVIEW"]):
        if mode == "LIBRARY":
            # Full card with edit actions
        elif mode == "REFERENCE":
            # Compact with navigation to source
```

## Modal/Dialog Button Docking

```python
# Primary actions MUST be always visible
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;"):
        # ... form content ...

    # Sticky bottom action bar
    with ui.element("div").style(
        "position: sticky; bottom: 0; padding: 1rem;"
    ):
        with ui.row().classes("justify-end"):
            ui.button("Cancel", on_click=dialog.close)
            ui.button("Save", on_click=save_handler)
```

## Checklists

### Styling Checklist
- [ ] No `gap-*` Tailwind classes (use inline style)
- [ ] No `height: 100%` inside `max-height` container
- [ ] Side-by-side layouts use `min-width: 0` on flex children
- [ ] Modal buttons are docked (always visible)

### Component Checklist
- [ ] Listed ALL locations where this data appears
- [ ] Designed component with modes for each context
- [ ] Same icon, typography, color coding everywhere

### Architecture Checklist
- [ ] Business logic in controller, not UI handlers
- [ ] Data fetching returns Pydantic models
- [ ] All user actions logged at start of handlers

## Reference Files

- [references/nicegui-styling.md](references/nicegui-styling.md) - Gap spacing, height issues, flexbox
- [references/product-thinking.md](references/product-thinking.md) - Component design, data display
- [references/ui-architecture.md](references/ui-architecture.md) - Controllers, state management

## Related Skills

- [/pythonista-typing](../pythonista-typing/SKILL.md) - Pydantic models for UI data
- [/pythonista-testing](../pythonista-testing/SKILL.md) - Testing controllers
- [/pythonista-async](../pythonista-async/SKILL.md) - Async UI patterns
- [/pythonista-patterning](../pythonista-patterning/SKILL.md) - Component reuse patterns

Overview

This skill helps developers build and maintain NiceGUI user interfaces with reliable layout and styling patterns. It focuses on predictable spacing, flexible layouts, reusable components, and keeping business logic in testable controllers. Use it to avoid common NiceGUI pitfalls and speed up UI development.

How this skill works

The skill inspects UI code for layout and styling anti-patterns (incorrect gap usage, improper height rules, missing min-width on flex children, non-docked modal actions). It recommends fixes, extracts controller patterns, and suggests component reuse strategies. It also provides checklists and code snippets for consistent implementation across pages.

When to use it

  • When creating or editing NiceGUI pages or components
  • When fixing layout or styling bugs (gap, height, flexbox issues)
  • When implementing dialogs, modals, or sticky action bars
  • When extracting business logic out of UI handlers into controllers
  • When designing reusable components that appear in multiple contexts

Best practices

  • Always use asyncio for UI code; avoid threads
  • Use three-layer architecture: data fetching → controller → UI
  • Use inline style for gap values; never rely on Tailwind gap-* classes
  • Avoid height: 100% inside max-height containers; prefer explicit percentage heights with scroll areas
  • Give flex children min-width: 0 for side-by-side charts and content
  • Dock primary modal actions with a sticky bottom action bar and keep UI handlers thin

Example use cases

  • Convert inline UI handlers into a PageController that returns testable updates
  • Fix a broken row spacing by replacing tailwind gap-* with style("gap: 0.75rem")
  • Build a reusable ItemReference component with modes (LIBRARY, REFERENCE, PREVIEW)
  • Implement a dialog with a scrollable content area and sticky action bar to keep Save visible
  • Lay out a chart next to a detail pane using flex: 1 and min-width: 0 to prevent overflow

FAQ

Why avoid Tailwind gap-* classes?

NiceGUI has rendering issues on some platforms; using inline style for gap ensures consistent spacing across environments.

How should I structure business logic for UI actions?

Extract logic into controller classes that fetch data and return UI update objects; keep UI handlers as small delegators that call controllers.