A tutorial series, DEV.to blog series — from your first HTML element to production-grade User Interfaces, all in pure Python. Modern Python web frameworks force developers into a split workflow: business logic lives in Python files with full IDE support, while presentation logic is exiled to template files that offer none of it. Template languages like Jinja2 introduce their own syntax for conditionals, loops, and variable access — syntax that your linter cannot check, your type checker cannot verify, and your debugger cannot step through. Every context variable passed across that boundary is a potential KeyError waiting to surface at runtime. Probo eliminates this divide entirely by making HTML a native Python construct — written, validated, and refactored with the same tools you already use for the rest of your codebase. PART 1: Introduction to Probo — Write HTML Entirely in Python What is Probo? Probo is a Python-first, declarative UI rendering framework. Instead of writing HTML in .html files or using template languages like Jinja2, you write everything in pure Python. No template files. No string concatenation. No f-strings full of angle brackets. Just Python functions and classes that are your HTML. The Two Flavors of Every Tag Every HTML tag in Probo comes in two forms: Flavor Example Returns Use Case Function (lowercase) div(), h1(), p() Rendered HTML Quick rendering, lightweight Class (uppercase) DIV(), H1(), P() SSDOM tree node Tree manipulation, streaming from probo import div, DIV # Function: returns a string immediately # return_list=True html_string = div("Hello World",) # → "Hello World" # Class: returns a tree node, call .render() to get the string node = DIV("Hello World",Id="main-title") # Because it's a Node, you can manipulate it dynamically node.add(div("Subtitle added later!")) html_string = node.render() # → 'Hello WorldSubtitle added later!' Enter fullscreen mode Exit fullscreen mode Note: by adding return_deque=True or return_list=True the output changes from string to respective return type Built-in Security Probo auto-escapes all text content by default via markup_escape. If a user submits alert('xss'), Probo renders it as harmless escaped text — no XSS vulnerabilities out of the box. from probo import p # User-submitted content is automatically escaped user_input = 'alert("hacked")' safe_html = p(user_input) # → "<script>alert("hacked")</script>" Enter fullscreen mode Exit fullscreen mode What You'll Learn in This Series By the end of this series, you'll be able to: Build full HTML pages in Python Navigate and manipulate a server-side DOM tree Bind dynamic data without prop-drilling Run a web server with routing, caching, and streaming Build interactive UIs with HTMX — with minimal to no JavaScript required Create reusable, skinnable component systems Deploy with Gunicorn or Uvicorn Let's get started! 👇
Introduction to Probo-ui — Write HTML Entirely in Python series
Full Article
Original Source
Read the full article at Dev →KhanList aggregates and links to publicly available news content. We do not host full articles from third-party sources. Always verify important information with original sources.