Skip to content
PlaygroundCoreTinker with data display.

Lists and tables

This page has five small apps about showing collections of data. Edit anything you like, and reload the page to reset the demos. The full story is Show a collection of items.

Bulleted and numbered

The same kind of data appears in two different components. Try swapping them and see which one reads better.

from drafter import *


@route
def index() -> Page:
    return Page([
        Header("The Plan"),
        "Ingredients (order does not matter):",
        BulletedList(["flour", "butter", "improbable optimism"]),
        "Steps (order very much matters):",
        NumberedList(["preheat", "mix", "regret nothing", "bake"])
    ])


start_server()

A list that grows from state

Each time the page is built, the list component displays whatever the state currently holds. Add something ridiculous to the list.

from drafter import *
from dataclasses import dataclass


@dataclass
class State:
    sightings: list[str]


@route
def index(state: State) -> Page:
    return Page(state, [
        Header("Backyard Sightings"),
        BulletedList(state.sightings),
        "Report a sighting:",
        TextBox("creature"),
        "\n",
        Button("Log it", "log")
    ])


@route
def log(state: State, creature: str) -> Page:
    state.sightings.append(creature)
    return index(state)


start_server(State(["one bold squirrel"]))

Table: dataclasses become rows

Field names become the header row. Add a weight_kg field to the dataclass and watch the table grow a column.

from drafter import *
from dataclasses import dataclass


@dataclass
class Pet:
    name: str
    species: str
    age: int


@route
def index() -> Page:
    return Page([
        Header("Residents"),
        Table([
            Pet("Ada", "corgi", 4),
            Pet("Babbage", "mutt", 6),
            Pet("Captain", "cat", 7),
            Pet("Domino", "cat", 2)
        ])
    ])


start_server()

DefinitionList: labeled facts

A single dataclass instance is rendered as pairs of terms and definitions. Try giving it a different dataclass.

from drafter import *
from dataclasses import dataclass


@dataclass
class Recipe:
    name: str
    minutes: int
    difficulty: str


@route
def index() -> Page:
    return Page([
        Header("Tonight"),
        DefinitionList(Recipe("impossible pie", 45, "brave"))
    ])


start_server()

ProgressBar and Meter: numbers as pictures

A ProgressBar shows how much of a task is complete, while a Meter shows a measurement within a range. Click the button and watch both change.

from drafter import *
from dataclasses import dataclass


@dataclass
class State:
    done: int


@route
def index(state: State) -> Page:
    return Page(state, [
        Header("Homework Machine"),
        "Problems done: " + str(state.done) + " of 10\n",
        ProgressBar(state.done, 10),
        "\nEnthusiasm remaining:\n",
        Meter(10 - state.done, 0, 10),
        "\n",
        Button("Do a problem", "work")
    ])


@route
def work(state: State) -> Page:
    if state.done < 10:
        state.done = state.done + 1
    return index(state)


start_server(State(3))

Where next

  • The Pet registry example uses tables to display real nested data.
  • The To-do list example grows and shrinks a list kept in state.