DEV Community

Cover image for SimpleStart: Build Interactive Web Apps in Pure Python
WY2024
WY2024

Posted on

SimpleStart: Build Interactive Web Apps in Pure Python

Every Python programmer eventually hits the same wall: the script works, but you want colleagues without a Python environment to use it — which means it needs a web page. Suddenly you're facing HTML, CSS, JavaScript, maybe npm and a build toolchain. Most people stop at that wall: the tool stays a command-line script, or a CSV gets emailed around instead.

SimpleStart is one answer to that wall: a pure-Python web framework. You write Python scripts; it renders the UI in the browser. For most scenarios you never touch HTML/CSS/JS — no node, no npm, no bundler. And when you truly need fine control, there are escape hatches (ss.css for styles, ss.loadvue for custom components — covered below).

This is an overview rather than a tutorial: what it is, how it works, what it can do, and where its limits are.

Who it's for

  • Data analysts — turn a pandas DataFrame into a page your team can actually open
  • Developers — internal tools fast: forms, reports, dashboards, small systems
  • Anyone who knows Python but doesn't want to learn front-end

How it works: two design decisions

  1. Event-driven. Clicks and inputs are handled by callbacks: you attach a Python function to a component, it runs at the moment of interaction, and only the affected elements get updated.
  2. Your script runs once. It executes at startup; after that, every interaction is handled by callbacks updating exactly what changed. The page never fully re-renders.

Point 2 deserves emphasis. Many people assume "Python to web" means "every click re-runs the whole script from top to bottom." SimpleStart is not that. It behaves like an event-driven application runtime: once the script has run, the world is just functions and callbacks. The bigger your app gets, the more this pays off.

A five-minute tour

Minimal app: a button and a callback

import simplestart as ss

ss.write("## Hello, SimpleStart!")
ss.write("Click the button and a message will be written to the page.")

def myclick():
    ss.write("Welcome to SimpleStart. :smile:")

ss.button("Click Me", type="primary", onclick=myclick)
Enter fullscreen mode Exit fullscreen mode

Save as app.py, run ss app.py, open http://localhost:8000. ss.write renders Markdown; onclick fires only at the moment of the click.

Reactive: variables bound to the page

import simplestart as ss

ss.session.name = "world"

ss.write("Change the text below - the page updates instantly, no reload.")
ss.write("Hello, @@name!")

def change_name(event):
    ss.session.name = event.value

ss.text_input("world", onchange=change_name)
Enter fullscreen mode Exit fullscreen mode

@@name binds that fragment of text to ss.session.name: change the variable inside a callback, and the page follows instantly. Not a single line of manual DOM or refresh code anywhere.

Data on screen: tables and charts

import simplestart as ss

mydata = [
    {"Month": "Jan", "Sales": 120, "Profit": 30},
    {"Month": "Feb", "Sales": 200, "Profit": 60},
    {"Month": "Mar", "Sales": 150, "Profit": 45},
]

ss.table(tableData=mydata, stripe=True)

ss.plot.bar(
    data={"A": 10, "B": 15, "C": 13, "D": 20, "E": 18},
    title="Basic Bar Chart",
)
Enter fullscreen mode Exit fullscreen mode

mydata is a plain Python list — pandas users are one df.to_dict("records") away from this. ss.table renders a striped table; ss.plot.bar builds an interactive chart (hover tooltips included) from a single dict — line and pie charts follow the same one-call API. Add a couple of filter widgets, and that's already a mini dashboard.

The component family

The building blocks an internal tool usually needs are all there:

  • Inputs: text field, date picker, slider, switch, radio, checkbox, select, file upload
  • Layout: cards, row/column grid, sidebar, dividers, spacing
  • Data display: tables, interactive bar/line/pie charts
  • Actions & feedback: buttons and button groups, semantic-colored text (success / warning / error)

Under the hood these come from mature Vue 3 component libraries (Element Plus, Vuetify) — the widgets you drive with Python keyword arguments are battle-tested enterprise controls: sizes, icons, loading and disabled states, all exposed as plain parameters.

Session state (ss.session), local persistence (ss.LocalStorage) and multi-page navigation (ss.openpage) are on board too.

When built-ins run out: bring your own

Official components can't cover everything. ss.loadvue loads a Vue single-file component you wrote into the app: Python receives its frontend events through handlers and passes data in through data — two-way communication that feels like a first-class component. You don't resurrect a whole front-end toolchain; you write exactly one component file for the one spot that needs it.

One step further: state-driven UI

On top of basic binding, ss.State is a reactive state container: pass it to a component parameter and the binding is done — components write changes back into state automatically, and state changes refresh every component bound to them. Written front-end before? It works like v-model. Never touched front-end? That's exactly why you don't need to learn it.

It changes how you organize an app. Take an auto-graded quiz: the answer is state, the right/wrong coloring is state, the score text is state — the grading function only reads and writes state, not a single line of "update the UI" code. Three questions, under 50 lines. Take user login: even "which card is visible" is bound to state — logging in is just flipping two booleans, and 37 lines cover login, error, welcome page and logout.

Both complete examples live in the tutorials/ directory of the GitHub repo — clone and run them as-is.

Reactive in more places

Besides ss.State, reactivity shows up in two easily-missed spots:

Component attributes are live. ss.button(...) returns the component object; assign to its attributes afterwards — change type from "default" to "success" and the button on the page changes color instantly, with derived styling (colors follow the type) updating automatically. Components are living Python objects, not one-shot markup.

Markdown has slots. ss.markdown accepts {slot#id} placeholders, and md.slot(id=...) fills them with any component: the prose explains, the component interacts, seamlessly inside the same content — the natural way to write tutorial or config pages that mix text with interaction. Inline attributes are supported too (markdown-it-attrs): *text*{.c-red} colors just that word.

The architecture trade-off

Most "Python to web" tools take one of two architectural routes, and the difference matters more as apps grow:

  • Script-rerun model: every interaction re-executes the entire script top to bottom. Low mental overhead — the script is the app — and great for top-to-bottom data reports: load, process, plot, done.
  • Event-driven model (SimpleStart): the script runs once; every interaction is a callback updating exactly what changed. State lives naturally in the session — you don't defend it from being wiped by a rerun, it's simply the app's skeleton. Updates are surgical instead of full-page.

Neither wins universally. For a one-off analysis report, script-rerun is pleasantly direct. For multi-step, state-heavy internal tools — login flows, quizzes, dashboards with filters — event-driven keeps both the code and the page stable as complexity grows.

Where it ends: honest limits

Fits: internal tools, form collection, data dashboards, teaching demos, personal mini-apps with login — anything where the logic lives in Python and the UI just needs to be good enough.

Not for: consumer-facing pages needing bespoke visuals, or public content sites that live on SEO. SimpleStart is an application runtime, not a site builder — it's the shortest path to putting Python logic in a browser, not pixel-level page control.

Status

SimpleStart is young but working: forms, data display, layout, state and custom components are all usable today, and the ecosystem keeps growing. If "just Python" sounds like your kind of idea, give it a try — issues and feedback are welcome on GitHub.

Dogfooding note: the online docs themselves are built with SimpleStart, and the interactive playground — edit example code and run it in the browser — is powered by ss.state.

Links

pip install simplestart — and turn that script only you can run into a page everyone can open.

Top comments (0)