BasecoatUI components for htmy.

Button

Example:

Variants:

Sizes:

Icons:


Code example:

from htmy import ComponentType, SafeStr, html

from htmui.basecoat.button import button
from htmui.basecoat.spinner import spinner

_plus_icon = SafeStr(
    '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" '
    'fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" '
    'stroke-linejoin="round" class="lucide lucide-plus">'
    '<path d="M5 12h14" /><path d="M12 5v14" /></svg>'
)
"""`plus` icon from https://lucide.dev."""

_branch_icon = SafeStr(
    '<svg xmlns="http://www.w3.org/2000/svg" data-icon="inline-start" width="24" height="24" '
    'viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" '
    'stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-git-branch">'
    '<path d="M15 6a9 9 0 0 0-9 9V3" />'
    '<circle cx="18" cy="6" r="3" /><circle cx="6" cy="18" r="3" /></svg>'
)
"""`git-branch` icon from https://lucide.dev, with inline-start icon spacing."""


def example() -> ComponentType:
    return html.div(
        html.h3("Variants:"),
        html.div(
            button("Primary"),
            button("Secondary", variant="secondary"),
            button("Outline", variant="outline"),
            button("Ghost", variant="ghost"),
            button("Link", variant="link"),
            button("Destructive", variant="destructive"),
            class_="flex flex-wrap items-center gap-2",
        ),
        html.h3("Sizes:"),
        html.div(
            button("Extra small", variant="outline", size="xs"),
            button("Small", variant="outline", size="sm"),
            button("Large", variant="outline", size="lg"),
            class_="flex flex-wrap items-center gap-2",
        ),
        html.h3("Icons:"),
        html.div(
            button(_branch_icon, "New branch", variant="outline", size="sm"),
            button(_plus_icon, variant="outline", size="icon", aria_label="Add"),
            button(spinner(data_icon="inline-start"), "Generating", disabled=True),
            class_="flex flex-wrap items-center gap-2",
        ),
        class_="flex flex-col gap-2",
    )

Component implementation:

For more details, see the BasecoatUI documentation.

from typing import Literal, TypeAlias

from htmy import ComponentType, PropertyValue, html, join_classes

__version__ = "0.2.0"
__framework__ = "BasecoatUI"
__framework_version__ = "1"
__framework_url__ = "https://basecoatui.com/components/button/"

ButtonVariant: TypeAlias = Literal["outline", "secondary", "ghost", "destructive", "link"]

ButtonSize: TypeAlias = Literal["xs", "sm", "default", "lg", "icon", "icon-xs", "icon-sm", "icon-lg"]


def button(
    *children: ComponentType,
    variant: ButtonVariant | None = None,
    size: ButtonSize | None = None,
    class_: str | None = None,
    **kwargs: PropertyValue,
) -> ComponentType:
    """
    Button component.

    Arguments:
        *children: Button content.
        variant: Button variant.
        size: Button size.
        class_: Extra CSS classes for the button.
        **kwargs: Extra attributes for the button.
    """
    if variant is not None:
        kwargs["data_variant"] = variant
    if size is not None:
        kwargs["data_size"] = size
    return html.button(*children, class_=join_classes("btn", class_), type_="button", **kwargs)