From d8817e42d526e03de2a69b042d50ae6587e37630 Mon Sep 17 00:00:00 2001 From: Randy Syring Date: Sat, 31 May 2025 15:48:32 -0400 Subject: [PATCH] Add support for dashed attrs refs https://github.com/Knio/dominate/issues/218 --- README.md | 44 ++++++++++++++++++++++++++++++++++++-------- dominate/__init__.py | 1 + dominate/dom_tag.py | 13 ++++++++++++- tests/test_html.py | 17 ++++++++++++++++- 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 78c5eb2..4f45182 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ For attributes `class` and `for` which conflict with Python's [reserved keywords |cls | fr | |className|htmlFor| |class_name|html_for| +|klass|phor| ```python @@ -139,27 +140,54 @@ print(test) ``` -Use `data_*` for [custom HTML5 data attributes](http://www.w3.org/html/wg/drafts/html/master/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes "HTML5 Data Attributes"). +You can also modify the attributes of tags through a dictionary-like interface: ```python -test = div(data_employee='101011') -print(test) +header = div() +header['id'] = 'header' +print(header) +``` +```html + +``` + +### Dashed Attributes + +Dashed attributes for `data_` and `aria_` are supported by default: + +```python +from dominate.tags import div + +print( + div(data_employee='101011'), + div(aria_role='button'), +) ``` ```html
+
``` -You can also modify the attributes of tags through a dictionary-like interface: +If you using a 3rd party library like HTMX, Unpoly, or AlpineJS that uses dashed attrs, you will +need to configure dominate accordingly: ```python -header = div() -header['id'] = 'header' -print(header) +import dominate +from dominate.tags import div + +dominate.dashed_attrs_add('hx_', 'x_') +print( + div(hx_target='/foo'), + div(x_show='open'), +) ``` + ```html - +
+
``` + Complex Structures ------------------ diff --git a/dominate/__init__.py b/dominate/__init__.py index becc617..9803bc6 100644 --- a/dominate/__init__.py +++ b/dominate/__init__.py @@ -1,2 +1,3 @@ from .version import __version__, version from .document import document +from .dom_tag import DASHED_ATTRS, dashed_attrs_add, dashed_attrs_reset diff --git a/dominate/dom_tag.py b/dominate/dom_tag.py index 15228ab..2cfddef 100644 --- a/dominate/dom_tag.py +++ b/dominate/dom_tag.py @@ -45,6 +45,17 @@ except ImportError: greenlet = None +# These prefixes will be converted to dashed html attributes. +DASHED_ATTRS = _DASHED_ATTRS_ORIG = ['data_', 'aria_'] + + +def dashed_attrs_add(*args: tuple[str]): + DASHED_ATTRS.extend(args) + + +def dashed_attrs_reset(): + DASHED_ATTRS = _DASHED_ATTRS_ORIG + # We want dominate to work in async contexts - however, the problem is # when we bind a tag using "with", we set what is essentially a global variable. # If we are processing multiple documents at the same time, one context @@ -447,7 +458,7 @@ def clean_attribute(attribute): attribute = attribute[1:] # Workaround for dash - special_prefix = any([attribute.startswith(x) for x in ('data_', 'aria_')]) + special_prefix = any([attribute.startswith(x) for x in DASHED_ATTRS]) if attribute in set(['http_equiv']) or special_prefix: attribute = attribute.replace('_', '-').lower() diff --git a/tests/test_html.py b/tests/test_html.py index 610c0c2..3437fb4 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -2,7 +2,7 @@ from dominate.tags import * from dominate.util import raw - +import dominate def test_arguments(): assert html(body(h1('Hello, pyy!'))).render() == \ @@ -366,3 +366,18 @@ class Card(div): assert Card().render() == '
' assert Card(tagname='div').render() == '
' + + +class TestDashedAttrs: + @pytest.fixture(autouse=True) + def reset(self): + yield + dominate.dashed_attrs_reset() + + def test_default(self): + assert div(hx_post='/clicked').render() == '
' + + def test_default(self): + dominate.dashed_attrs_add('hx_', 'un_') + assert div(hx_post='/clicked').render() == '
' + assert div(un_post='/clicked').render() == '
'