SVG grammar
Last Updated: 2026-06-10 Status: 🟢 APPROVATO — allineato al contratto v0.8.0. Maintainer: core team.
SVG 1.1 grammar. 56 elements covering shapes, paths, text, gradients, filters.
Purpose
Produce SVG markup for vector graphics: charts, icons, diagrams,
illustrations. Pairs with SvgRenderer for serialization (XML
self-closing tags with a space, e.g. <rect />, kebab-case
attribute names where required).
Quick start
from genro_builders.contrib.svg import SvgBuilder
class Chart(SvgBuilder):
def main(self, root):
svg = root.svg(viewBox="0 0 100 100")
svg.rect(x=10, y=10, width=80, height=80, fill="red")
svg.circle(cx=50, cy=50, r=20, fill="white")
c = Chart(); c.create()
print(c.render())
Output (single line, default mode):
<svg viewBox="0 0 100 100"><rect x="10" y="10" width="80" height="80" fill="red" /><circle cx="50" cy="50" r="20" fill="white" /></svg>
Elements
56 elements declared in svg_elements.py. Grouped by purpose:
Group |
Examples |
|---|---|
Root / container |
|
Shapes (leaf) |
|
Text |
|
Gradients / patterns |
|
Filters |
|
Animation |
|
References |
|
Most shapes are leaves (sub_tags=""). Containers use * as
sub-tags (any SVG child accepted).
Common patterns
Kebab-case attributes
SVG accepts attributes like stroke-width, stroke-dasharray,
font-size. Python kwargs use underscores; the renderer converts:
svg.line(x1=0, y1=0, x2=100, y2=0,
stroke="black", stroke_width=2, stroke_dasharray="5,5")
→ <line x1="0" y1="0" x2="100" y2="0" stroke="black" stroke-width="2" stroke-dasharray="5,5" />
Chaining leaves with ._
Most SVG content is leaves. Use ._ to keep the call stream
flowing:
svg = root.svg(viewBox="0 0 100 100")
svg.rect(x=10, y=10, width=80, height=80, fill="red")\
._.rect(x=20, y=20, width=60, height=60, fill="blue")\
._.circle(cx=50, cy=50, r=10, fill="white")
viewBox and coordinate space
The renderer does not validate viewBox — pass it as a string.
Coordinates inside the SVG can be ints, floats, or strings; they
serialize unchanged.
Render
SvgRenderer produces SVG markup through the universal walk:
RendererBase.render(source, **opts) recurses on the source bag,
and SvgRenderer.rendered_item(node, item, runtime_attrs, **opts)
emits the fragment for each node. Void tags emit with a space
before the close (<rect />), in line with SVG convention. Pretty
printing is not yet implemented for SVG.
Validation rules
The root must be
<svg>(or, when used as a sub-builder, the<svg>of the host HTML page).<tspan>and<textPath>only valid under<text>.<stop>only valid under gradients.Container elements accept any SVG child (
sub_tags="*"); the schema does not enforce semantic constraints (e.g. “filters inside<defs>”).
Validation errors raise ValueError at create() time.
Worked examples
Examples under src/genro_builders/contrib/svg/examples/:
01_introduction/— three-view (.py,.ipynb,.svg).Plus legacy single-view examples (
badge_sheet/,bar_chart/,card_shadow/,concentric_circles/,house_icon/) that predate the three-view format.
Known limitations
Pretty printing is not implemented for SVG.
pretty=Trueis ignored.No automatic xmlns declarations. The user adds
xmlns="http://www.w3.org/2000/svg"on the root<svg>if the output is consumed standalone.Animation (
<animate>and friends) is in the schema but the renderer does not specialize for the SMIL syntax — attributes pass through verbatim.
References
Source:
src/genro_builders/contrib/svg/.Renderer:
src/genro_builders/contrib/svg/svg_renderer.py.Schema:
src/genro_builders/contrib/svg/svg_elements.py.Contract:
roadmap/architecture-contract.md.