I got tired of this:
- Write logic in
views.py - Jump to HTML
- Add a condition
- Go back to Python
- Repeat 50 times
- And if a template has a layout issue… good luck finding the element
At some point it clicked:
Templates aren’t UI. They’re just strings with logic inside.
So I built Probo UI — now in a stable 1.4.0 version where UI is no longer text…
It’s Python objects you can edit, reuse, and compose — literally what Probo stands for:
Python Rendered Objects for Backend-Oriented User Interfaces
The Idea in One Line
UI = Python object tree (SSDOM), not static HTML
Probo turns UI into a mutable structure, not a final string.
1. Write UI Like This (Not Templates)
Example 1 — Basic Component
from probo import DIV, H1, P
def profile_card(username, role):
return DIV(
H1(username),
P(f"Role: {role}"),
Class="profile-card"
)
print(profile_card("Youness", "user").render())
No template file. No {% %}.
Just Python.
2. Now Mutate It (This Is the Shift)
Example 2 — Dynamic Styling (No Template Rewrite)
card = profile_card("Youness", "admin")
if card and user_status == 'admin':
card.attr_manager.add_class("admin-border")
card.style_manager.color = 'red'
card.style_manager.margin_top = '50px'
print(card.render())
You didn’t:
- duplicate templates
- add
{% if %} - inject class strings
You just modified the object.
3. Build Real Components (Reusable Blocks)
Example 3 — Real Component with Data
from probo import div, h1, ul, li, strong
def user_card(username):
user_id = f"User_{username}"
skills = ["python", "django", "docker"]
return div(
h1(username, strong(user_id)),
ul(*[li(s) for s in skills]),
Class="card"
)
This is not “template rendering”.
This is:
component composition in Python
4. Permission-Based UI (No Template Logic Hell)
Example 4 — Conditional Rendering (Built-in)
from probo.components import Component, ComponentState, StateProps
from probo import div, ul # functional tags (not OOP)
def user_card(username):
props = StateProps(required=True, prop_equal_to={"username": "admin"})
data = {"skills": ["python", "django"]}
state = ComponentState(d_data=data)
return Component(
name="UserCard",
template=div(ul()),
state=state,
props={"username": username}
)
print(user_card("Admin").render()) # empty
print(user_card("admin").render()) # shows data
Instead of:
{% if user.is_admin %}- scattered logic
You get:
structured, state-driven UI
5. Live Demo — Multi-Role UI (Customer / Staff / Admin) + HTMX
👉 https://youness00mojahid.pythonanywhere.com/
This is a real app built with Probo UI + Django + HTMX.
It demonstrates how one system can generate multiple interfaces from the same components.
🧑💻 Customer UI
- Clean product/service views
- Minimal controls
- Limited interaction
Same components — just rendered with different state.
🧑🔧 Staff UI
- Edit/manage controls appear
- More data becomes visible
- Components extend behavior
No new templates — just mutated components.
🛠️ Admin UI
- Full control panels
- Management actions
- Expanded UI
Same base UI — dynamically transformed.
⚡ Dynamic Interactions (HTMX)
- No full page reloads
- Server-rendered partial updates
- Lightweight interactivity
Workflow:
Python = structure + logic
HTMX = interaction
Browser = render
🧠 What This Demo Proves
- One UI system → multiple roles
- No template duplication
- Dynamic UI without frontend frameworks
💡 The Key Takeaway
Instead of:
customer.htmlstaff.htmladmin.html
You build:
one UI system that adapts itself
6. The Core Concept (Short Version)
SSDOM (Server-Side DOM):
- UI is a Python tree
- You can modify it before rendering
- HTML is just output
This avoids:
- template fragmentation
- string manipulation
- scattered logic
7. It Scales
| Elements | Total Time |
|---|---|
| 1,000 | 0.0222s |
| 10,000 | 0.9401s |
| 25,000 | 5.8194s |
| 75,000 | 77.1450s |
Key points:
- Constant-time mutations (~0.001s)
- Designed to handle large UI trees
📊 About the Performance Chart
The benchmark results are not isolated measurements—they are part of a continuous scaling curve.
The performance results depend on the rendering paradigm used inside Probo UI.
Probo UI supports a multi-paradigm rendering model:
Functional tags (stateless / O(1)-style) → optimized for large-scale rendering
OOP / class-based nodes (mutable SSDOM objects) → richer features, slightly heavier cost
In optimized functional mode, the same 75,000-node test can render significantly faster (sub-second in controlled cases).
You can view the full progression from 100 → 75,000 nodes here:
👉 https://mojahid-0-youness.github.io/probo/performance_chart/
This chart reflects how Probo UI behaves under increasing load across real rendering scenarios.
The goal is not just raw speed, but predictable scaling behavior across:
- small UI components
- medium applications
- large, nested UI trees
8. Why This Matters
Traditional:
- Python → logic
- HTML → UI
- Templates → glue
Probo:
- Python → logic + UI
- HTML → output
You get:
- easier refactoring
- reusable components
- no context switching
- fewer silent template errors
9. Framework Agnostic by Design
Probo UI is not tied to Django or any specific backend framework.
It works as a UI layer that sits above any Python web framework.
Because Probo UI builds a Server-Side DOM (SSDOM), it only needs:
- Python to construct the UI tree
- A render step to output HTML
That means it can be used with:
- Django
- Flask
- FastAPI
- Or any custom WSGI/ASGI application
The framework only handles routing and requests.
Probo handles the UI structure.
10. Try It
pip install probo-ui
Docs:
https://mojahid-0-youness.github.io/probo/
Repo:
https://github.com/MojahiD-0-YouneSS/probo
Final Thought
If your backend is Python…
why are you still writing UI in HTML?
Your Turn
- Would you replace templates with Python?
- Or is this overengineering?
I want honest feedback.
Probo UI 1.4.0 — stable, usable, and just getting started.
Top comments (0)