Package: htbuilder
htbuilder — tiny HTML string builder for Pythonhtbuilder lets you build HTML strings using a purely functional syntax in Python.
Why use templating languages when you can just use functions?(PS: If you like this, check outjsbuildwhich
lets you build JavaScript strings by simply annotating Python functions!)InstallationJust PIP it!pipinstallhtbuilderUsageJust import tags likedivwithfrom htbuilder import div, then call them:# Import any tag you want from htbuilder, and it just works!# (This syntax requires Python 3.7+. See below for an alternate syntax)fromhtbuilderimportdivdom=div('Hello world!')Then you can get the string output by callingstr()on it:str(dom)# Returns '<div>Hello world!</div>'...which means you can also justprint()to see it in the terminal:print(dom)# Prints '<div>Hello world!</div>'To specify attributes, call the tag builder with keyword args:print(div(id='sidebar',foo='bar'))# Prints '<div id="sidebar" foo="bar"></div>'To specify both attributes and children, first specify the attributes using
keyword args, then pass the children afterwardsinside a new
set of parentheses:print(div(id='sidebar',foo='bar')("Hello world!"))# Prints '<div id="sidebar" foo="bar">Hello world!</div>'This is required because Python doesn't allow you to pass keyword argumentsbeforeyou pass normal arguments.Multiple childrenWant to output multiple children? Just pass them all as arguments:fromhtbuilderimportdiv,ul,li,imgdom=(div(id='container')(ul(_class='greetings')(li('hello'),li('hi'),li('whattup'),)))print(dom)# Prints this (but without added spacing):# <div id="container">#   <ul class="greetings">#     <li>hello</li>#     <li>hi</li>#     <li>whattup</li>#   </ul># </div>Programmatically add childrenYou can also pass any iterable to specify multiple children, which means you can
simply use things like generator expressions for great awesome:fromhtbuilderimportdiv,ul,li,imgimage_paths=['http://myimages.com/foo1.jpg','http://myimages.com/foo2.jpg','http://myimages.com/foo3.jpg',]dom=(div(id='container')(ul(_class='image-list')(li(img(src=image_path,_class='large-image'))forimage_pathinimage_paths)))print(dom)# Prints:# <div id="container">#   <ul class="image-list">#     <li><img src="http://myimages.com/foo1.jpg" class="large-image"/></li>#     <li><img src="http://myimages.com/foo2.jpg" class="large-image"/></li>#     <li><img src="http://myimages.com/foo3.jpg" class="large-image"/></li>#   </ul># </div>Conditionally add elementsAnd because it's just Python, you can use an if/else expression to conditionally
insert elements:use_bold=Truedom=(div(b("bold text")ifuse_boldelse"normal text"))print(dom)# Prints: <div><b>bold text</b></div>StylingWe provide helpers to write styles without having to pass huge style strings as
arguments. Instead, just use handy builders likestyles(),classes(),fonts(), along with helpers you can import from theunitsandfuncsmodules.# styles, classes, and fonts are special imports to help build attribute strings.fromhtbuilderimportdiv,styles,classes,fonts# You can import anything from .units and .funcs to make it easier to specify# units like "%" and "px", as well as functions like "rgba()" and "rgba()".fromhtbuilder.unitsimportpercent,pxfromhtbuilder.funcsimportrgba,rgbbottom_margin=10is_big=Truedom=(div(_class=classes('btn',big=is_big)style=styles(color='black',font_family=fonts('Comic Sans','sans-serif'),margin=px(0,0,bottom_margin,0),padding=(px(10),percent(5))box_shadow=[(0,0,px(10),rgba(0,0,0,0.1)),(0,0,'2px',rgb(0,0,0)),],)))# Prints:# <div#   class="btn big"#   style="#     color: black;#     font-family: "Comic Sans", "sans-serif";#     margin: 0 0 10px 0;#     padding: 10px 5%;#     box-shadow: 0 0 10px rgba(0, 0, 0, 0.1), 0 0 2px rgb(0, 0, 0);#   "></div>Underscores are magicUse underscores instead of dashesLike most popular languages, Python doesn't support dashes in identifiers. So if you want to build
an element that includes dashes in the tag name or attributes, like<my-element foo-bar="baz">, you can
do so by using underscores instead:fromhtbuilderimportmy_elementdom=my_element(foo_bar="baz")print(dom)# Prints:# <my-element foo-bar="baz"></my-element>Prefix with underscore to avoid reserved wordsThe wordclassis reserved in Python, so if you want to set an element'sclassattribute you
should prepend it with an underscore like this:dom=div(_class="myclass")print(dom)# Prints:# <div class="myclass"></div>This works because underscores preceding or following any identifier are automatically stripped away
for you.Working with Python < 3.7If using Python < 3.7, the import should look like this instead:fromhtbuilderimportHdiv=H.divul=H.ulli=H.liimg=H.img# ...etc