htbuilder


Namehtbuilder JSON
Version 0.9.0 PyPI version JSON
download
home_pagehttps://github.com/tvst/htbuilder
SummaryA purely-functional HTML builder for Python. Think JSX rather than templates.
upload_time2025-01-09 07:00:26
maintainerNone
docs_urlNone
authorThiago Teixeira
requires_python>=3.7
licenseApache 2
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # htbuilder — tiny HTML string builder for Python

htbuilder 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 out [jsbuilder](https://github.com/tvst/jsbuilder) which
lets you build JavaScript strings by simply annotating Python functions!)

## Installation

Just PIP it!

```py
pip install htbuilder
```

## Usage

Just import tags like `div` with `from htbuilder import div`, then call them:

```py
# Import any tag you want from htbuilder, and it just works!
from htbuilder import div

dom = div('Hello world!')
```

Then you can get the string output by calling `str()` on it:

```py
str(dom)
# Returns '<div>Hello world!</div>'
```

...which means you can also just `print()` to see it in the terminal:

```py
print(dom)
# Prints '<div>Hello world!</div>'
```

To specify attributes, call the tag builder with keyword args:

```py
print(
  div(id='sidebar', foo='bar')
)
# Prints '<div id="sidebar" foo="bar"></div>'
```

To specify both attributes and children, you can just use regular Python argument
notation:

```py
print(
  div("Hello world!", id='sidebar', foo='bar')
)
# Prints '<div id="sidebar" foo="bar">Hello world!</div>'
```

...but some might find this order a bit weird! It doesn't the ordering you might be used to in HTML.

So we also support two other notations:

1. You can then pass the children afterwards **inside a new set of parentheses**:

   ```py
   print(
     div(id='sidebar', foo='bar')(
       "Hello world!"
     )
   )
   # Prints '<div id="sidebar" foo="bar">Hello world!</div>'
   ```

1. Or you can pass the children inside `[]` for added clarity:

   ```py
   print(
     div(id='sidebar', foo='bar')[
       "Hello world!"
     ]
   )
   # Prints '<div id="sidebar" foo="bar">Hello world!</div>'
   ```

All these notations are totally valid and fine! Just pick the one you like best.

## Multiple children

Want to output multiple children? Just pass them all as arguments:

```py
from htbuilder import div, ul, li, img

dom = (
  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 children

You can also pass any iterable to specify multiple children, which means you can
simply use things like generator expressions for great awesome:

```py
from htbuilder import div, ul, li, img

image_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'))
      for image_path in image_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 elements

And because it's just Python, you can use an if/else expression to conditionally
insert elements:

```py
use_bold = True

dom = (
  div(
    b("bold text") if use_bold else "normal text"
  )
)

print(dom)
# Prints: <div><b>bold text</b></div>
```

## Modify elements imperatively

Elements accumulate the arguments you send to them, so you can intersperse DOM and code very
naturally:

```py
parent = div()

for url in img_urls:
  child = img(src="https://foo.com/myimage.png")
  child.width = 200
  child.height = 100

  if alt_text:
    child.alt = alt_text
  else:
    child.alt = "The developer forgot to enter a description. Go scold them!"

  parent(child)
```

## Styling

We provide helpers to write styles without having to pass huge style strings as
arguments. Instead, just use handy builders like `styles()`, `classes()`,
`fonts()`, along with helpers you can import from the `units` and `funcs`
modules.

```py
# styles, classes, and fonts are special imports to help build attribute strings.
from htbuilder import div, 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()".
from htbuilder.units import percent, px
from htbuilder.funcs import rgba, rgb

bottom_margin = 10
is_big = True

dom = (
  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 magic

### Use underscores instead of dashes

Like 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:

```py
from htbuilder import my_element

dom = my_element(foo_bar="baz")

print(dom)
# Prints:
# <my-element foo-bar="baz"></my-element>
```

### Prefix with underscore to avoid reserved words

The word `class` is reserved in Python, so if you want to set an element's `class` attribute you
should prepend it with an underscore like this:

```py
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.



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/tvst/htbuilder",
    "name": "htbuilder",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": null,
    "author": "Thiago Teixeira",
    "author_email": "me@thiagot.com",
    "download_url": "https://files.pythonhosted.org/packages/be/88/0f48d1125168e9eea33879ea820000702533d103f1123d27ca69839a0db4/htbuilder-0.9.0.tar.gz",
    "platform": null,
    "description": "# htbuilder \u2014 tiny HTML string builder for Python\n\nhtbuilder lets you build HTML strings using a purely functional syntax in Python.\nWhy use templating languages when you can just use functions?\n\n(PS: If you like this, check out [jsbuilder](https://github.com/tvst/jsbuilder) which\nlets you build JavaScript strings by simply annotating Python functions!)\n\n## Installation\n\nJust PIP it!\n\n```py\npip install htbuilder\n```\n\n## Usage\n\nJust import tags like `div` with `from htbuilder import div`, then call them:\n\n```py\n# Import any tag you want from htbuilder, and it just works!\nfrom htbuilder import div\n\ndom = div('Hello world!')\n```\n\nThen you can get the string output by calling `str()` on it:\n\n```py\nstr(dom)\n# Returns '<div>Hello world!</div>'\n```\n\n...which means you can also just `print()` to see it in the terminal:\n\n```py\nprint(dom)\n# Prints '<div>Hello world!</div>'\n```\n\nTo specify attributes, call the tag builder with keyword args:\n\n```py\nprint(\n  div(id='sidebar', foo='bar')\n)\n# Prints '<div id=\"sidebar\" foo=\"bar\"></div>'\n```\n\nTo specify both attributes and children, you can just use regular Python argument\nnotation:\n\n```py\nprint(\n  div(\"Hello world!\", id='sidebar', foo='bar')\n)\n# Prints '<div id=\"sidebar\" foo=\"bar\">Hello world!</div>'\n```\n\n...but some might find this order a bit weird! It doesn't the ordering you might be used to in HTML.\n\nSo we also support two other notations:\n\n1. You can then pass the children afterwards **inside a new set of parentheses**:\n\n   ```py\n   print(\n     div(id='sidebar', foo='bar')(\n       \"Hello world!\"\n     )\n   )\n   # Prints '<div id=\"sidebar\" foo=\"bar\">Hello world!</div>'\n   ```\n\n1. Or you can pass the children inside `[]` for added clarity:\n\n   ```py\n   print(\n     div(id='sidebar', foo='bar')[\n       \"Hello world!\"\n     ]\n   )\n   # Prints '<div id=\"sidebar\" foo=\"bar\">Hello world!</div>'\n   ```\n\nAll these notations are totally valid and fine! Just pick the one you like best.\n\n## Multiple children\n\nWant to output multiple children? Just pass them all as arguments:\n\n```py\nfrom htbuilder import div, ul, li, img\n\ndom = (\n  div(id='container')[\n    ul(_class='greetings')[\n      li('hello'),\n      li('hi'),\n      li('whattup'),\n    ]\n  ]\n)\n\nprint(dom)\n\n# Prints this (but without added spacing):\n# <div id=\"container\">\n#   <ul class=\"greetings\">\n#     <li>hello</li>\n#     <li>hi</li>\n#     <li>whattup</li>\n#   </ul>\n# </div>\n```\n\n## Programmatically add children\n\nYou can also pass any iterable to specify multiple children, which means you can\nsimply use things like generator expressions for great awesome:\n\n```py\nfrom htbuilder import div, ul, li, img\n\nimage_paths = [\n  'http://myimages.com/foo1.jpg',\n  'http://myimages.com/foo2.jpg',\n  'http://myimages.com/foo3.jpg',\n]\n\ndom = (\n  div(id='container')[\n    ul(_class='image-list')[\n      li(img(src=image_path, _class='large-image'))\n      for image_path in image_paths\n    ]\n  ]\n)\n\nprint(dom)\n# Prints:\n# <div id=\"container\">\n#   <ul class=\"image-list\">\n#     <li><img src=\"http://myimages.com/foo1.jpg\" class=\"large-image\"/></li>\n#     <li><img src=\"http://myimages.com/foo2.jpg\" class=\"large-image\"/></li>\n#     <li><img src=\"http://myimages.com/foo3.jpg\" class=\"large-image\"/></li>\n#   </ul>\n# </div>\n```\n\n## Conditionally add elements\n\nAnd because it's just Python, you can use an if/else expression to conditionally\ninsert elements:\n\n```py\nuse_bold = True\n\ndom = (\n  div(\n    b(\"bold text\") if use_bold else \"normal text\"\n  )\n)\n\nprint(dom)\n# Prints: <div><b>bold text</b></div>\n```\n\n## Modify elements imperatively\n\nElements accumulate the arguments you send to them, so you can intersperse DOM and code very\nnaturally:\n\n```py\nparent = div()\n\nfor url in img_urls:\n  child = img(src=\"https://foo.com/myimage.png\")\n  child.width = 200\n  child.height = 100\n\n  if alt_text:\n    child.alt = alt_text\n  else:\n    child.alt = \"The developer forgot to enter a description. Go scold them!\"\n\n  parent(child)\n```\n\n## Styling\n\nWe provide helpers to write styles without having to pass huge style strings as\narguments. Instead, just use handy builders like `styles()`, `classes()`,\n`fonts()`, along with helpers you can import from the `units` and `funcs`\nmodules.\n\n```py\n# styles, classes, and fonts are special imports to help build attribute strings.\nfrom htbuilder import div, styles, classes, fonts\n\n# You can import anything from .units and .funcs to make it easier to specify\n# units like \"%\" and \"px\", as well as functions like \"rgba()\" and \"rgba()\".\nfrom htbuilder.units import percent, px\nfrom htbuilder.funcs import rgba, rgb\n\nbottom_margin = 10\nis_big = True\n\ndom = (\n  div(\n    _class=classes('btn', big=is_big)\n    style=styles(\n        color='black',\n        font_family=fonts('Comic Sans', 'sans-serif'),\n        margin=px(0, 0, bottom_margin, 0),\n        padding=(px(10), percent(5))\n        box_shadow=[\n            (0, 0, px(10), rgba(0, 0, 0, 0.1)),\n            (0, 0, '2px', rgb(0, 0, 0)),\n        ],\n    )\n  )\n)\n\n# Prints:\n# <div\n#   class=\"btn big\"\n#   style=\"\n#     color: black;\n#     font-family: \"Comic Sans\", \"sans-serif\";\n#     margin: 0 0 10px 0;\n#     padding: 10px 5%;\n#     box-shadow: 0 0 10px rgba(0, 0, 0, 0.1), 0 0 2px rgb(0, 0, 0);\n#   \"></div>\n```\n\n## Underscores are magic\n\n### Use underscores instead of dashes\n\nLike most popular languages, Python doesn't support dashes in identifiers. So if you want to build\nan element that includes dashes in the tag name or attributes, like `<my-element foo-bar=\"baz\">`, you can\ndo so by using underscores instead:\n\n```py\nfrom htbuilder import my_element\n\ndom = my_element(foo_bar=\"baz\")\n\nprint(dom)\n# Prints:\n# <my-element foo-bar=\"baz\"></my-element>\n```\n\n### Prefix with underscore to avoid reserved words\n\nThe word `class` is reserved in Python, so if you want to set an element's `class` attribute you\nshould prepend it with an underscore like this:\n\n```py\ndom = div(_class=\"myclass\")\n\nprint(dom)\n# Prints:\n# <div class=\"myclass\"></div>\n```\n\nThis works because underscores preceding or following any identifier are automatically stripped away\nfor you.\n\n\n",
    "bugtrack_url": null,
    "license": "Apache 2",
    "summary": "A purely-functional HTML builder for Python. Think JSX rather than templates.",
    "version": "0.9.0",
    "project_urls": {
        "Homepage": "https://github.com/tvst/htbuilder"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "be880f48d1125168e9eea33879ea820000702533d103f1123d27ca69839a0db4",
                "md5": "fe3d3c4736b61797933d256a0d18a7e4",
                "sha256": "58c0bc5502c1a46b42ae9e074c43ec0f6fdc24ed334936cb17e1ed5a8938aee2"
            },
            "downloads": -1,
            "filename": "htbuilder-0.9.0.tar.gz",
            "has_sig": false,
            "md5_digest": "fe3d3c4736b61797933d256a0d18a7e4",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 10591,
            "upload_time": "2025-01-09T07:00:26",
            "upload_time_iso_8601": "2025-01-09T07:00:26.189692Z",
            "url": "https://files.pythonhosted.org/packages/be/88/0f48d1125168e9eea33879ea820000702533d103f1123d27ca69839a0db4/htbuilder-0.9.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-01-09 07:00:26",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "tvst",
    "github_project": "htbuilder",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "htbuilder"
}
        
Elapsed time: 4.02247s