Skip to main content

High-performance reactive web framework for Python. Build dashboards, internal tools, and data apps with a Streamlit-like API but 10x faster.

Project description

image

Cacao

High-performance reactive web framework for Python.

Build dashboards, internal tools, and data apps with a simple API — real WebSocket reactivity, not full-page reruns.

PyPI Version Downloads Python License CI GitHub Pages

React WebSocket Starlette GitHub Stars


Features · Quick Start · Examples · Components · Architecture · Static Builds · Contributing


v2.0 — Complete rewrite with signal-based reactivity, session-scoped state, plugin hooks, and a Streamlit-like API that doesn't re-run your entire script.

Quick Start

pip install cacao
import cacao as c

c.title("Hello, Cacao!")
c.text("Welcome to the simplest Python web framework")
cacao run app.py

That's it — 3 lines of Python and you have a live web app with hot reload.


Why Cacao?

Feature Cacao Streamlit
Reactivity Signal-based (only changed values update) Full script re-run on every interaction
State Session-scoped by design st.session_state bolt-on
Updates WebSocket streaming (instant) HTTP polling (laggy)
Multi-user Isolated sessions built-in Shared state issues
API Context managers + decorators Magic globals
Static export cacao build — no server needed Not supported

Features

Reactive Signals

count = c.signal(0, name="count")

@c.on("increment")
async def increment(session, event):
    count.set(session, count.get(session) + 1)

Signals are the core of Cacao. When a value changes, only the affected components update — no full-page reruns, no diffing your entire tree.

60+ Built-in Components

Layouts, forms, charts, display elements, navigation — everything you need out of the box.

Multi-Page Apps

with c.page("/"):
    c.title("Home")

with c.page("/settings"):
    c.title("Settings")

Hash-based routing works both in server mode and static builds.

Static Builds

cacao build app.py

Export your app to a static site (HTML + JS + CSS) that runs entirely in the browser. Deploy to GitHub Pages, Netlify, or any static host — no Python server required.

Plugin Hooks & Auth

Extensible architecture with plugin registration, authentication hooks, and notification toasts.

Dark & Light Themes

c.config(theme="dark")  # or "light"

Examples

Interactive Counter

import cacao as c

c.config(title="Counter")
count = c.signal(0, name="count")

@c.on("increment")
async def increment(session, event):
    count.set(session, count.get(session) + 1)

@c.on("decrement")
async def decrement(session, event):
    count.set(session, count.get(session) - 1)

c.title("Counter")

with c.card():
    c.metric("Count", count)
    with c.row():
        c.button("-", on_click="decrement", variant="secondary")
        c.button("+", on_click="increment")

Dashboard with Charts

import cacao as c

c.config(title="Sales Dashboard", theme="dark")
sales = c.sample_sales_data()

c.title("Sales Dashboard")

with c.row():
    c.metric("Revenue", "$45,231", trend="+20.1%", trend_direction="up")
    c.metric("Orders", "1,247", trend="+12.5%", trend_direction="up")
    c.metric("Customers", "842", trend="+5.3%", trend_direction="up")

with c.row():
    with c.col(span=8):
        with c.card("Revenue Trend"):
            c.line(sales, x="date", y="revenue", area=True)
    with c.col(span=4):
        with c.card("By Category"):
            c.pie(sales[:5], values="revenue", names="category", donut=True)

with c.card("Recent Transactions"):
    c.table(sales[:10], columns=["date", "category", "revenue", "orders"])

More examples in the examples/ directory:

Example Description
simple/hello.py Minimal hello world
simple/counter.py Interactive counter with signals
simple/metrics.py KPI dashboard
simple/dashboard.py Full dashboard with charts
chat/app.py Chat application
todo/server.py Todo list app
analytics_dashboard/ Analytics dashboard

Components

Layout

Component Description
row() Horizontal flex layout
col(span=N) Column with 12-grid span
grid() CSS grid layout
container() Centered container
stack() Vertical stack
split() Side-by-side split
hero() Hero section
card() Card container
tabs() / tab() Tabbed content
accordion() Collapsible sections
modal() Modal dialog
panel() Sliding panel
app_shell() Full app layout with sidebar

Display

Component Description
title() / text() Typography
markdown() Markdown with optional TOC
code() Syntax-highlighted code
metric() KPI metric with trend
table() Data table
json_view() Interactive JSON viewer
badge() / alert() Status indicators
progress() Progress bar
image() / video() Media
timeline() Timeline display
diff() Side-by-side diff viewer
breadcrumb() Navigation breadcrumb

Form

Component Description
button() Button with variants
input_field() Text input
textarea() Multi-line input
select() Dropdown select
checkbox() / switch() Toggle inputs
slider() Range slider
date_picker() Date picker
search_input() Search with suggestions
file_upload() File upload
chat() Chat input interface

Charts

Component Description
line() / area() Line and area charts
bar() Bar chart
pie() / donut() Pie and donut charts
scatter() Scatter plot
gauge() Gauge meter
heatmap() Heatmap
radar() Radar chart
funnel() Funnel chart
treemap() Treemap

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                         PYTHON SERVER                           │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌───────────────┐  │
│  │ Signals  │  │ Sessions │  │  Events  │  │ WebSocket/HTTP│  │
│  │ (state)  │──│ (per-    │──│ (typed   │──│    Server     │  │
│  │          │  │  client) │  │  async)  │  │  (Starlette)  │  │
│  └──────────┘  └──────────┘  └──────────┘  └───────┬───────┘  │
└────────────────────────────────────────────────────┼───────────┘
                                                     │ JSON
                                                     │ WebSocket
┌────────────────────────────────────────────────────┼───────────┐
│                      REACT CLIENT                  │           │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────┴──────┐   │
│  │  Hooks   │  │Components│  │  Event   │  │   State     │   │
│  │useCacao()│──│ (60+ UI) │──│Dispatcher│──│   Store     │   │
│  └──────────┘  └──────────┘  └──────────┘  └─────────────┘   │
└─────────────────────────────────────────────────────────────────┘

Data flow:

Python API → JSON definition → WebSocket → React renders
     ↑                                         ↓
Signal.set() ←── Event handler ←── User action

CLI

cacao run app.py                     # Run with hot reload
cacao run app.py --port 3000         # Custom port
cacao run app.py --no-reload         # Disable hot reload
cacao create my-dashboard            # Scaffold a new project
cacao build app.py                   # Build static site
cacao build app.py --base-path /repo # For GitHub Pages subdirectory

Static Builds

Cacao generates static sites that run entirely in the browser — no Python server required.

cacao build app.py

Output:

dist/
├── index.html    # Your app
├── cacao.js      # Runtime + built-in handlers
└── cacao.css     # Styles

Built-in client-side handlers for common operations:

  • Encoders — Base64, URL, HTML entities, JWT decode
  • Generators — UUID, passwords, Lorem Ipsum
  • Converters — JSON/YAML, case conversion, number bases
  • Text — Statistics, regex testing
  • Crypto — Hash generation, HMAC

Deploy to GitHub Pages:

# .github/workflows/deploy.yml
- run: pip install cacao
- run: cacao build app.py --base-path /${{ github.event.repository.name }}

See cacao-tools for a full static site example.


Tech Stack

Layer Technology
Backend Python 3.10+, Starlette, Uvicorn, WebSocket
Frontend React 18, Chart.js, LESS
Build esbuild, hatchling
State Signal-based reactivity with session scoping
Deployment Static export, GitHub Pages, any ASGI server

Project Structure

cacao/
├── __init__.py          # Package exports
├── simple.py            # Streamlit-like API (import cacao as c)
├── server/              # Core server
│   ├── ui.py            # 60+ UI components
│   ├── chart.py         # Chart components
│   ├── signal.py        # Signal & Computed reactivity
│   ├── session.py       # Session management
│   ├── events.py        # Event handling
│   ├── server.py        # HTTP + WebSocket server
│   └── data.py          # Data utilities
├── cli/                 # CLI (run, build, create)
├── frontend/            # Frontend source (devs only)
│   ├── src/components/  # React components
│   ├── src/styles/      # LESS styles
│   ├── src/handlers/    # Static build handlers
│   └── dist/            # Build output
└── examples/            # Example apps

Contributing

Contributions are welcome! See the repo issues for ideas.

fork → feature branch → commit → push → pull request

Cacao — Reactive Python UIs, made simple.

Report Bug · Request Feature

Made with care by Juan Denis

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cacao-2.0.18.tar.gz (162.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cacao-2.0.18-py3-none-any.whl (775.0 kB view details)

Uploaded Python 3

File details

Details for the file cacao-2.0.18.tar.gz.

File metadata

  • Download URL: cacao-2.0.18.tar.gz
  • Upload date:
  • Size: 162.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for cacao-2.0.18.tar.gz
Algorithm Hash digest
SHA256 dd3d74d706ec3c3f3f5225ba067daa896f77cab8cc1894a6685730da5e662106
MD5 e762f5b288d21f85b1c2dd188f10c514
BLAKE2b-256 40b1550a1a5a9988e60672790a980350a7265cf846783bde4451098db6831cd7

See more details on using hashes here.

File details

Details for the file cacao-2.0.18-py3-none-any.whl.

File metadata

  • Download URL: cacao-2.0.18-py3-none-any.whl
  • Upload date:
  • Size: 775.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for cacao-2.0.18-py3-none-any.whl
Algorithm Hash digest
SHA256 a7fe755a496b7bf2539034d7eb63edccc643d6dd59ecbaf1bd66df71d9934635
MD5 cffadf3838a29e4653efe56ca968aeb3
BLAKE2b-256 20aa849461d4b92d26f6890fbbefa4fe494215287f9713b4c412429ee17ce4bf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page