Dominate Python HTML Generation and DOM Manipulation
Dominate is a Python library for creating and manipulating HTML documents using an elegant DOM API. It allows you to write HTML pages in pure Python very concisely, which eliminate the need to learn another template language, and to take advantage of the more powerful features of Python.
At a glance
- What is it?
- Dominate lets Python programs construct and modify HTML through element objects instead of a separate template language. It fits code-driven document generation, although its LGPL-3.0-or-newer license and compact DOM model require review before adoption.
- Who is it for?
- Adopt Dominate when HTML is part of a Python program and its element tree is easier to manipulate than a template or literal string. Do not choose it merely for static pages, when a template editor offers better authoring support, or when the LGPL-3.0-or-newer obligations are unacceptable for the intended distribution.
- Can I use it commercially?
- Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 167 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Dominate's Code-Based HTML Document Model
Dominate addresses Python developers who need to generate HTML as part of application logic. The README presents the library as a way to create HTML pages in Python without learning another template language. Its central abstraction is a DOM-like hierarchy in which tags are classes and their constructors accept child elements, text, and keyword attributes.
That model differs from a file-oriented template workflow. Instead of separating a template document from runtime values, a program can use loops, conditionals, Python variables, and helper functions while building the tree. The navigation example constructs an ordered list from an iterable, which makes the generation logic visible in ordinary Python control flow.
The target user is therefore not someone who only wants an editable HTML file. Dominate is better aligned with reports, generated interfaces, server-side document assembly, and other cases where a Python program must decide the document structure. It also fits codebases that already expose application data through Python objects. Its tradeoff is that designers and front-end developers cannot use this library alone as a visual template editor. The repository does not document browser tooling, live preview, or a separate design-time workflow.
From Python Elements to an HTML Tree
A Dominate document starts with document objects and tag classes imported from dominate.tags. Context managers such as doc.head and doc place elements under the correct document branches. Calling add() or using += attaches children, while render(), __str__, or __unicode__ produces the HTML representation. The README states that render() returns the human-readable representation of these nodes.
The tree is mutable at several documented points. Keyword arguments establish attributes during element creation, dictionary assignment changes an existing attribute, and indexed assignment can replace a child. This is more useful than simple string concatenation when an application needs to construct a hierarchy first and modify selected parts afterward.
Dominate also handles names that conflict with Python syntax. For example, cls becomes the HTML class attribute and fr becomes the for attribute. The underscore forms _class and _for are available too, as are className, htmlFor, class_name, and html_for. Custom HTML5 data attributes use data_ syntax, with an underscore converted into the attribute's hyphenated form.
The documentation does not describe selector-based querying, browser-compatible DOM events, or JavaScript execution. It presents a Python-side document tree and serializer, so adopting Dominate should not be confused with adopting a complete browser DOM implementation.
Installing Dominate and Rendering a First Page
The README recommends installing the package from PyPI with pip. The project metadata requires Python 3.10 or later and classifies the package as operating system independent.
Run this command in the environment where the generated-document dependency should be installed:
pip install dominateA successful installation makes dominate and its tag classes available to Python. The first example below creates a document, adds stylesheet and script references to its head, builds navigation from a Python list, adds body content, and prints the serialized document.
import dominate
from dominate.tags import *
doc = dominate.document(title='Dominate your HTML')
with doc:
with div(id='header').add(ol()):
for i in ['home', 'about', 'contact']:
li(a(i.title(), href='/%s.html' % i))
with div():
attr(cls='body')
p('Lorem ipsum..')
print(doc)The README's corresponding output contains an html element with head and body branches. Under the header, the three list items become links for Home, About, and Contact. Calling print(doc) requests the node's HTML representation, so the program can inspect a complete serialized document without starting a web server.
Rendering Controls for Readable or Compact HTML
Pretty printing is enabled by default, with one HTML element per line and two spaces of indentation. The behavior is not just a global toggle with one fixed output shape. Dominate exposes an element-level __pretty attribute and render() options named pretty, indent, and xhtml. Rendering options propagate to descendant nodes.
The difference is visible when a div contains a span. Pretty rendering places the child on an indented line:
a = div(span('Hello World'))
print(a.render())Disabling pretty rendering requests compact output instead:
print(a.render(pretty=False))This matters for applications with different output contracts. Human-facing source may be easier to inspect with indentation, while generated output may have size or exact-format requirements. The documentation says that __pretty defaults to True except for certain element types such as pre, which reduces the risk that formatting inside preformatted content is treated as ordinary indentation.
The README does not document escaping guarantees, browser normalization, or conformance validation against a complete HTML specification. Developers should therefore treat render() as serialization of the constructed Dominate tree, not as proof that the resulting page passes an independent HTML validator.
Dominate Boundaries Compared with Static HTML Construction
The practical alternative is to build the required HTML directly as Python strings, or to place the page in a separate template system. Direct strings keep output close to literal markup and require the application to manage quotes, structure, indentation, and insertion points itself. Dominate instead represents elements as objects, adds attributes through keyword arguments or dictionary access, and attaches children through constructors, add(), +=, or context managers.
That difference becomes valuable when the structure changes. A literal HTML page is a poor fit for navigation assembled from an unknown number of items, but Dominate can accept an iterable of generated li elements. The same tree can then be rendered as pretty or compact text without manually assembling every line break.
Dominate is also the wrong tool when the page is genuinely static and only needs occasional hand editing. A plain HTML file keeps presentation structure directly in markup and does not require reviewers to read Python to understand it. The README does not document visual authoring, template inheritance, form helpers, asset pipelines, or integration with a frontend build system. Those omissions matter more if the project is primarily a designer-facing page template than a Python-generated document.
Maintenance, Python Compatibility, and LGPL Costs
The repository is not archived. Its last push was on 2026-05-09. The listed releases are 2.9.1 from 2023-12-24, 2.9.0 from 2023-11-16, and 2.8.0 from 2023-05-21. This means repository activity continued after the most recent listed release, but the README and release list do not establish a release schedule.
The current pyproject.toml declares requires-python = ">=3.10" and lists Python 3.10 through 3.14, along with PyPy. A Python application on an older interpreter cannot adopt the current package metadata without changing its runtime. Upgrade review should therefore cover both the interpreter baseline and any local code that depends on element behavior.
The declared license is LGPL-3.0-or-newer, and the project classifier identifies the GNU Lesser General Public License v3. This is a distribution consideration rather than a claim about a particular legal outcome. Teams should inspect LICENSE.txt and determine how their use and distribution model relates to the license text. The LGPL designation may also matter more for a linked or distributed application than for a short internal script, but the repository files do not provide legal advice.
Editorial conclusion
Adopt Dominate when HTML is part of a Python program and its element tree is easier to manipulate than a template or literal string. Do not choose it merely for static pages, when a template editor offers better authoring support, or when the LGPL-3.0-or-newer obligations are unacceptable for the intended distribution. Before adoption, verify Python 3.10 compatibility in your environment, inspect the LGPL-3.0-or-newer obligations for your distribution model, and render a representative document with the required pretty, indentation, and XHTML settings.
Frequently asked questions
How do I install Dominate for Python?
The README recommends `pip install dominate`. Current project metadata requires Python 3.10 or later.
How does Dominate render an HTML document in Python?
Construct elements from `dominate.tags`, add them to a document or parent node, then call `print(doc)`, `str(node)`, or `render()`. The README states that nodes provide their HTML representation through `__str__`, `__unicode__`, and `render()`.
Can Dominate generate navigation from a Python list?
Yes. Its tag constructors accept iterables, and the README shows a generator producing `li` and `a` elements from menu data.
Which Python versions does Dominate support?
The project metadata requires Python 3.10 or later and lists Python 3.10, 3.11, 3.12, 3.13, and 3.14.
What license does Dominate use?
The project metadata declares `LGPL-3.0-or-newer`. Review the repository's `LICENSE.txt` for the applicable license text.
Official sources
Was this useful?