Skip to content

Widgets

In Klix, “widgets” are the reusable output and interaction building blocks layered on top of the renderer and input engine. This page focuses on the stateful and higher-level pieces that are most useful when you build richer CLI flows.

For the raw component entry points, see Input Components and Output Components.

Spinner

Use spinner(...) when the user needs immediate feedback that something is happening.

python
spinner = session.ui.output.spinner("Preparing release", color="accent")
spinner.start()
await asyncio.sleep(0.5)
spinner.update("Uploading artifacts")
await asyncio.sleep(0.5)
spinner.stop()

Why it exists:

  • long operations feel broken without visible activity
  • a spinner is lighter than a progress bar when total work is unknown

Internally:

  • rich-capable terminals use a live status spinner
  • fallback renderers print plain progress messages instead

Progress Bar

Use progress(...) when work has a meaningful total.

python
progress = session.ui.output.progress(total=5, label="Warmup", color="success")
progress.start()
for _ in range(5):
    await asyncio.sleep(0.2)
    progress.update(advance=1)
progress.stop()

You can also update by absolute completion or adjust the total dynamically.

Panel, Card, And Table As Display Widgets

These are the display primitives most apps will use:

python
session.ui.output.card(
    "Cards are just bordered content with a semantic name.",
    title="Card",
    border_color="info",
)

session.ui.output.table(
    headers=["Component", "State"],
    rows=[["spinner", "idle"], ["progress", "running"]],
)

They are simple on purpose. Klix expects apps to combine small widgets rather than rely on a giant declarative UI system.

Interactive Selection Widgets

Although technically exposed through session.ui.input, selection widgets behave like interactive UI components:

  • select(...)
  • multiselect(...)
  • fuzzy(...)
  • toggle(...)

Use them when a command becomes more of a guided flow than a raw slash invocation.

python
profile = await session.ui.input.select(
    ["Gemini", "Claude", "Klix", "Local"],
    label="Pick a profile",
)

Building A Small Interactive Flow

python
@app.command("/setup", help="Run interactive setup")
async def setup(session: klix.Session) -> None:
    profile = await session.ui.input.select(
        ["default", "performance", "debug"],
        label="Profile",
    )
    features = await session.ui.input.multiselect(
        ["logging", "metrics", "tracing"],
        label="Enable features",
    )

    spinner = session.ui.output.spinner("Applying configuration", color="accent")
    spinner.start()
    await asyncio.sleep(0.5)
    spinner.stop()

    session.ui.output.panel(
        f"Profile: {profile}\nFeatures: {', '.join(features) or 'none'}",
        title="Configuration Applied",
        border_color="success",
    )

Terminal Behavior To Understand

Widgets in Klix are cooperative, not magical:

  • they work within the prompt-driven model
  • layout regions stay lightweight
  • rich widgets degrade in fallback mode
  • selection dialogs depend on an interactive terminal

That keeps the framework small, but it means you should design flows that are clear even without a fully dynamic screen.

Common Mistakes

  • Starting a spinner and forgetting to stop it.
  • Using a progress bar when the total is unknown.
  • Treating selection widgets as persistent screen elements instead of transient interactions.
  • Overbuilding UI complexity that the coarse layout system is not meant to own.

Released under the MIT License.