Skip to content

htmforge.components

htmforge.components.alert.Alert(**data)

Bases: Component

Rendert eine Alert-Box mit optionalem Dismiss-Button.

Source code in htmforge\core\component.py
def __init__(self, **data: Any) -> None:  # noqa: ANN401
    """Initialisiert die Komponente und blockiert Klassen ohne ``render``."""
    if getattr(type(self), "__htmforge_missing_render__", False):
        raise TypeError(
            f"Can't instantiate abstract class {type(self).__name__} "
            "without a concrete render() implementation"
        )
    super().__init__(**data)

render()

Erstellt ein <div> mit Variantenklasse und optionalem Schliessen.

Source code in htmforge\components\alert.py
def render(self) -> Element:
    """Erstellt ein ``<div>`` mit Variantenklasse und optionalem Schliessen."""
    children: list[Element | str] = [self.message]
    if self.dismissible:
        children.append(
            button(
                "×",
                type="button",
                cls="alert-close",
                aria_label=self.close_label,
                onclick="this.closest('.alert').remove()",
            )
        )
    return div(*children, cls=f"alert alert-{self.variant.value}")

htmforge.components.alert.AlertVariant

Bases: StrEnum

Unterstuetzte Alert-Varianten.

htmforge.components.badge.Badge(**data)

Bases: Component

Rendert ein kleines Inline-Label mit Variantenklasse.

Example

Badge(text="3", variant=BadgeVariant.DANGER).to_html() '3'

Source code in htmforge\core\component.py
def __init__(self, **data: Any) -> None:  # noqa: ANN401
    """Initialisiert die Komponente und blockiert Klassen ohne ``render``."""
    if getattr(type(self), "__htmforge_missing_render__", False):
        raise TypeError(
            f"Can't instantiate abstract class {type(self).__name__} "
            "without a concrete render() implementation"
        )
    super().__init__(**data)

render()

Erstellt ein <span> mit Variantenklasse.

Source code in htmforge\components\badge.py
def render(self) -> Element:
    """Erstellt ein ``<span>`` mit Variantenklasse."""
    return span(self.text, cls=f"badge badge-{self.variant.value}")

htmforge.components.badge.BadgeVariant

Bases: StrEnum

Unterstuetzte Badge-Varianten.

htmforge.components.breadcrumb.Breadcrumb(**data)

Bases: Component

Rendert eine Breadcrumb-Navigation als <nav> mit geordneter Liste.

Items sind (label, url)-Tupel. url=None markiert die aktuelle Seite und wird als <span> gerendert.

Example

Breadcrumb(items=[("Home", "/"), ("Aktuell", None)]).to_html()

contains Home and Aktuell

Source code in htmforge\core\component.py
def __init__(self, **data: Any) -> None:  # noqa: ANN401
    """Initialisiert die Komponente und blockiert Klassen ohne ``render``."""
    if getattr(type(self), "__htmforge_missing_render__", False):
        raise TypeError(
            f"Can't instantiate abstract class {type(self).__name__} "
            "without a concrete render() implementation"
        )
    super().__init__(**data)

render()

Erstellt <nav> mit <ol> und <li>-Eintraegen.

Source code in htmforge\components\breadcrumb.py
def render(self) -> Element:
    """Erstellt ``<nav>`` mit ``<ol>`` und ``<li>``-Eintraegen."""
    list_items: list[Element] = []
    last_index = len(self.items) - 1

    for index, (label, href) in enumerate(self.items):
        is_current = href is None or index == last_index
        if is_current:
            list_items.append(
                li(
                    span(label, aria_current="page"),
                    cls="breadcrumb-item active",
                )
            )
        else:
            list_items.append(
                li(
                    a(label, href=href),
                    cls="breadcrumb-item",
                )
            )

    return nav(ol(*list_items, cls="breadcrumb"), aria_label="breadcrumb")

htmforge.components.table.DataTable(**data)

Bases: Component

Rendert eine einfache Datentabelle mit optionalem HTMX-Reload.

Source code in htmforge\core\component.py
def __init__(self, **data: Any) -> None:  # noqa: ANN401
    """Initialisiert die Komponente und blockiert Klassen ohne ``render``."""
    if getattr(type(self), "__htmforge_missing_render__", False):
        raise TypeError(
            f"Can't instantiate abstract class {type(self).__name__} "
            "without a concrete render() implementation"
        )
    super().__init__(**data)

render()

Erstellt div.table-wrapper > table.table mit thead/tbody.

Source code in htmforge\components\table.py
def render(self) -> Element:
    """Erstellt ``div.table-wrapper > table.table`` mit ``thead``/``tbody``."""
    header_row = tr(*(th(header) for header in self.headers))

    body_rows: list[Element]
    if self.rows:
        body_rows = [tr(*(td(cell) for cell in row)) for row in self.rows]
    else:
        colspan = max(len(self.headers), 1)
        body_rows = [
            tr(td(self.empty_message, colspan=colspan, cls="table__empty"))
        ]

    attrs: dict[str, object] = {}
    if self.hx_url is not None:
        attrs["hx_get"] = self.hx_url
        attrs["hx_trigger"] = HxTrigger.LOAD

    return div(
        table(
            thead(header_row),
            tbody(*body_rows),
            cls="table",
            **attrs,
        ),
        cls="table-wrapper",
    )

htmforge.components.form_field.FormField(**data)

Bases: Component

Rendert ein beschriftetes Eingabefeld mit optionaler Fehleranzeige.

Example

from htmforge.components.form_field import FormField, InputType field = FormField( ... name="username", ... label_text="Benutzername", ... required=True, ... ) "required" in field.to_html() True

Source code in htmforge\core\component.py
def __init__(self, **data: Any) -> None:  # noqa: ANN401
    """Initialisiert die Komponente und blockiert Klassen ohne ``render``."""
    if getattr(type(self), "__htmforge_missing_render__", False):
        raise TypeError(
            f"Can't instantiate abstract class {type(self).__name__} "
            "without a concrete render() implementation"
        )
    super().__init__(**data)

render()

Erstellt div > label + input [+ div.field-error].

Source code in htmforge\components\form_field.py
def render(self) -> Element:
    """Erstellt ``div > label + input [+ div.field-error]``."""
    fid = self.field_id or self.name.replace(" ", "-")

    children: list[Element] = [
        label(
            self.label_text,
            for_=fid,
            aria_required="true" if self.required else None,
        ),
        input(
            type=self.input_type.value,
            name=self.name,
            id=fid,
            value=self.value or None,
            placeholder=self.placeholder or None,
            required=True if self.required else None,
            aria_required="true" if self.required else None,
        ),
    ]

    if self.error:
        children.append(div(self.error, cls="field-error"))

    return div(*children)

htmforge.components.form_field.InputType

Bases: StrEnum

Unterstuetzte <input>-Typen.

htmforge.components.modal.Modal(**data)

Bases: Component

Trigger-Button + leeres Dialog-Overlay, Inhalt wird per HTMX geladen.

Renders
Fields

modal_id: str — unique HTML id for the

trigger_label: str — label on the trigger button hx_url: str — URL to load modal content from hx_target: str = "" — overrides default target if set close_label: str = "Schließen"

Source code in htmforge\core\component.py
def __init__(self, **data: Any) -> None:  # noqa: ANN401
    """Initialisiert die Komponente und blockiert Klassen ohne ``render``."""
    if getattr(type(self), "__htmforge_missing_render__", False):
        raise TypeError(
            f"Can't instantiate abstract class {type(self).__name__} "
            "without a concrete render() implementation"
        )
    super().__init__(**data)

render()

Erstellt den Trigger-Button und das <dialog>-Overlay.

Source code in htmforge\components\modal.py
def render(self) -> Element:
    """Erstellt den Trigger-Button und das ``<dialog>``-Overlay."""
    body_id = f"{self.modal_id}-body"
    target = self.hx_target or f"#{body_id}"

    return div(
        button(
            self.trigger_label,
            type="button",
            data_modal_target=self.modal_id,
            cls="modal-trigger",
            hx_get=self.hx_url,
            hx_target=target,
            hx_swap=HxSwap.INNER_HTML,
        ),
        dialog(
            div(id=body_id, cls="modal-body"),
            form(
                button(self.close_label, cls="modal-close"),
                method="dialog",
            ),
            id=self.modal_id,
            cls="modal",
        ),
        raw(
            "<script>"
            "document.querySelectorAll('[data-modal-target]').forEach(function(btn){"
            "btn.addEventListener('click',function(){"
            "var id=btn.getAttribute('data-modal-target');"
            "var dlg=document.getElementById(id);"
            "if(dlg)dlg.showModal();"
            "});"
            "});"
            "</script>"
        ),
        cls="modal-wrapper",
    )

htmforge.components.pagination.Pagination(**data)

Bases: Component

Rendert Previous/Next und Seitenlinks fuer HTMX-Navigation.

Source code in htmforge\core\component.py
def __init__(self, **data: Any) -> None:  # noqa: ANN401
    """Initialisiert die Komponente und blockiert Klassen ohne ``render``."""
    if getattr(type(self), "__htmforge_missing_render__", False):
        raise TypeError(
            f"Can't instantiate abstract class {type(self).__name__} "
            "without a concrete render() implementation"
        )
    super().__init__(**data)

render()

Erstellt eine <ul> mit Seitenlinks inklusive Previous/Next.

Source code in htmforge\components\pagination.py
def render(self) -> Element:
    """Erstellt eine ``<ul>`` mit Seitenlinks inklusive Previous/Next."""
    items: list[Element] = [self._previous_link()]

    for page in range(1, self.total_pages + 1):
        if page == self.current_page:
            items.append(li(a(str(page), href="#"), cls="active"))
        else:
            items.append(
                li(
                    a(
                        str(page),
                        href="#",
                        **self._link_attrs(self.hx_url.format(page=page)),
                    )
                )
            )

    items.append(self._next_link())
    return ul(*items, cls="pagination")

htmforge.components.search_input.SearchInput(**data)

Bases: Component

Text-Input mit automatischem hx-trigger keyup-Debounce.

     </div>
Fields

name: str — input name attribute search_url: str — URL for hx-get (custom field, not Component.hx_get) search_target: str — CSS selector for swap target (custom field, not Component.hx_target) placeholder: str = "Suchen…" debounce_ms: int = 300 indicator: str = "" — optional hx-indicator selector

Source code in htmforge\core\component.py
def __init__(self, **data: Any) -> None:  # noqa: ANN401
    """Initialisiert die Komponente und blockiert Klassen ohne ``render``."""
    if getattr(type(self), "__htmforge_missing_render__", False):
        raise TypeError(
            f"Can't instantiate abstract class {type(self).__name__} "
            "without a concrete render() implementation"
        )
    super().__init__(**data)

render()

Erstellt den Such-Input mit Debounce und optionalem Indicator.

Source code in htmforge\components\search_input.py
def render(self) -> Element:
    """Erstellt den Such-Input mit Debounce und optionalem Indicator."""
    return div(
        input(
            type="search",
            name=self.name,
            placeholder=self.placeholder,
            hx_get=self.search_url,
            hx_trigger=hx_keyup_delay(self.debounce_ms),
            hx_target=self.search_target,
            hx_indicator=self.indicator or None,
        ),
        cls="search-input-wrapper",
    )

htmforge.components.page.Page(**data)

Bases: Component

Abstrakte Basisklasse fuer vollstaendige HTML-Dokumente mit DOCTYPE.

Subklassen implementieren :meth:_body_content um den Seiteninhalt bereitzustellen. :meth:to_html haengt automatisch <!DOCTYPE html> voran.

Example

from htmforge.components.page import Page from htmforge.core.element import Element

class MyPage(Page): ... users: list[str] = [] ... ... def _body_content(self) -> list[Element | str | None]: ... from htmforge.elements import li, ul ... return [ul(*[li(u) for u in self.users])] ... page = MyPage(title="Users", users=["Ada", "Grace"]) page.to_html().startswith("<!DOCTYPE html>") True

Source code in htmforge\core\component.py
def __init__(self, **data: Any) -> None:  # noqa: ANN401
    """Initialisiert die Komponente und blockiert Klassen ohne ``render``."""
    if getattr(type(self), "__htmforge_missing_render__", False):
        raise TypeError(
            f"Can't instantiate abstract class {type(self).__name__} "
            "without a concrete render() implementation"
        )
    super().__init__(**data)

render()

Rendert das vollstaendige <html>-Dokument ohne DOCTYPE.

Source code in htmforge\components\page.py
def render(self) -> Element:
    """Rendert das vollstaendige ``<html>``-Dokument ohne DOCTYPE."""
    head_children: list[Any] = [meta(charset=self.charset)]

    if self.description:
        head_children.append(meta(name="description", content=self.description))

    head_children.append(title(self.title))

    for css_url in self.css_urls:
        head_children.append(link(rel="stylesheet", href=css_url))

    if self.inline_css:
        head_children.append(style(raw(self.inline_css)))

    body_children: list[Any] = [c for c in self._body_content() if c is not None]

    for js_url in self.js_urls:
        body_children.append(script(src=js_url))

    return html(
        head(*head_children),
        body(*body_children),
    )

to_html()

Rendert das vollstaendige Dokument inklusive <!DOCTYPE html>.

Source code in htmforge\components\page.py
def to_html(self) -> str:
    """Rendert das vollstaendige Dokument inklusive ``<!DOCTYPE html>``."""
    return "<!DOCTYPE html>" + self.render().to_html()