HTML attributes
Helpers for Vue-like class/style merging on HTML elements.
format_attrs function
Format an attribute dict into an HTML attribute string.
Truerenders the bare attribute (disabled);FalseandNoneomit the attribute entirely.classandstylevalues may use the structured forms; they are normalized here, somerge_attrsoutput and hand-built dicts render the same. When they normalize to an empty string the attribute is omitted (an emptyclass=""would read as a boolean attribute under citry's HTML rules).- Everything else renders
key="value", escaped; values with__html__pass through unescaped.
Example::
format_attrs({"class": ["btn", {"active": True}], "disabled": True, "data-id": 3})
# -> 'class="btn active" disabled data-id="3"'
merge_attrs function
Merge attribute dicts left to right into one dict.
Every key resolves last-one-wins, except class and style: their values from all dicts are collected and combined per normalize_class / normalize_style, so several sources can contribute classes and style properties without overwriting each other.
Key order in the result is the order each key was first seen, so a later override does not move an attribute.
Example::
merge_attrs(
{"class": "btn", "id": "first"},
{"class": {"active": True}, "id": "second"},
)
# -> {"class": "btn active", "id": "second"}
normalize_class function
normalize_class(value: ClassValue) -> strTurn a structured class value into a plain class string.
- A string is used as-is (stripped).
- A dict keeps only the keys whose value is truthy.
- A list may mix strings, dicts, and nested lists. Each item converts to a
{class_name: bool}dict (strings split on whitespace, allTrue) and the dicts merge left to right, so a later falsy entry removes a class added earlier.
Example::
normalize_class(["btn btn-lg", {"active": True, "hidden": False}])
# -> "btn btn-lg active"
normalize_style function
normalize_style(value: StyleValue) -> strTurn a structured style value into an inline CSS string.
- A string is used as-is (stripped).
- A dict renders each entry as
property: value;. Property names are used as written (kebab-case); numbers render bare (width: 100). - A list may mix strings, dicts, and nested lists. Strings are parsed into property dicts (see
parse_string_style) and the dicts merge left to right, so the last value of a property wins.
Two special values steer a merge: None skips the entry (an earlier value for the property stands), and a literal False removes the property entirely, even if set earlier.
Example::
normalize_style(["color: red; width: 100px", {"color": "green", "width": False}])
# -> "color: green;"
parse_string_style function
Parse an inline CSS string into a property dict.
Strips /* ... */ comments. Declarations split on ; except inside parentheses, so url(data:image/png;base64,...) survives. A declaration without a : is dropped.
Example::
parse_string_style("color: red; width: 100px; /* note */")
# -> {"color": "red", "width": "100px"}