Skip to content

Export Button

The ExportButton component generates export buttons for CSV, Excel, JSON, and PDF downloads.

Quick Start

ExportButton("Export", endpoint="/api/export", export_format="csv")

Usage Scenarios

Excel Export

ExportButton("Download Excel", endpoint="/api/export", export_format="xlsx", filename="report.xlsx")

JSON with Extra Params

ExportButton("Export JSON", endpoint="/api/export", export_format="json", extra_params={"include_archived": True})

HTMX Download

ExportButton("Export", endpoint="/api/export", export_format="csv", use_hx=True, hx_target="#result", variant="success")

Parameter Reference

Parameter Type Default Description
label str "Export" Button label text
endpoint str \| None None Export endpoint URL
export_format "csv" \| "xlsx" \| "json" \| "pdf" "csv" Export file format
filename str \| None None Suggested filename for download
method "get" \| "post" "get" HTTP method
use_hx bool False Use HTMX for the request
hx_target str \| None None HTMX target selector
hx_swap str \| None "none" HTMX swap style
push_url bool False Push URL for HTMX GET flows
variant str \| None UNSET Bootstrap variant
outline bool True Use outline style
icon str \| None "download" Bootstrap icon name
extra_params dict \| None None Extra query/body parameters
**kwargs Any - Additional HTML attributes

Accessibility

  • Button uses semantic <button> or <a> tag based on method.
  • Icons use aria-hidden="true".
  • Download attribute is set when filename is provided.

API Reference

faststrap.components.forms.export_button.ExportButton(label='Export', *, endpoint=None, export_format='csv', filename=None, method='get', use_hx=False, hx_target=None, hx_swap='none', push_url=False, variant=UNSET, outline=True, icon='download', extra_params=None, **kwargs)

Export button for CSV/Excel/JSON/PDF downloads.

Source code in src/faststrap/components/forms/export_button.py
@register(category="forms")
@beta
def ExportButton(
    label: str = "Export",
    *,
    endpoint: str | None = None,
    export_format: ExportFormat = "csv",
    filename: str | None = None,
    method: ExportMethod = "get",
    use_hx: bool = False,
    hx_target: str | None = None,
    hx_swap: str | None = "none",
    push_url: bool = False,
    variant: VariantType | None = UNSET,
    outline: bool = True,
    icon: str | None = "download",
    extra_params: dict[str, Any] | None = None,
    **kwargs: Any,
) -> Any:
    """Export button for CSV/Excel/JSON/PDF downloads."""
    cfg = resolve_defaults(
        "ExportButton",
        export_format=export_format,
        method=method,
        use_hx=use_hx,
        hx_swap=hx_swap,
        push_url=push_url,
        variant=variant,
        outline=outline,
    )
    c_format = cfg.get("export_format", export_format)
    c_method = cfg.get("method", method)
    c_use_hx = cfg.get("use_hx", use_hx)
    c_hx_swap = cfg.get("hx_swap", hx_swap)
    c_push_url = cfg.get("push_url", push_url)
    c_variant = cast(VariantType, cfg.get("variant", variant) or "secondary")
    c_outline = cfg.get("outline", outline)

    params: dict[str, Any] = {"format": c_format}
    if filename:
        params["filename"] = filename
    if extra_params:
        params.update(extra_params)

    user_cls = kwargs.pop("cls", "")
    attrs: dict[str, Any] = {"cls": merge_classes("faststrap-export-button", user_cls)}
    attrs.update(convert_attrs(kwargs))

    if endpoint:
        url = _build_url(endpoint, params)
    else:
        url = None

    if c_method == "get":
        if url:
            if c_use_hx:
                attrs.update(
                    {
                        "hx_get": url,
                        "hx_target": hx_target,
                        "hx_swap": c_hx_swap,
                    }
                )
                if c_push_url:
                    attrs["hx_push_url"] = "true"
            else:
                attrs["href"] = url
                if filename:
                    attrs["download"] = filename
        return Button(
            label,
            variant=c_variant,
            outline=c_outline,
            icon=icon,
            **attrs,
        )

    if c_use_hx:
        if url:
            attrs.update(
                {
                    "hx_post": url,
                    "hx_target": hx_target,
                    "hx_swap": c_hx_swap,
                }
            )
            if c_push_url:
                attrs["hx_push_url"] = "true"
        return Button(
            label,
            variant=c_variant,
            outline=c_outline,
            icon=icon,
            **attrs,
        )

    if not url:
        return Button(
            label,
            variant=c_variant,
            outline=c_outline,
            icon=icon,
            **attrs,
        )

    hidden_inputs = [
        FTInput(type="hidden", name="format", value=c_format),
    ]
    if filename:
        hidden_inputs.append(FTInput(type="hidden", name="filename", value=filename))
    if extra_params:
        for key, value in extra_params.items():
            normalized = _normalize_query_value(value)
            if normalized is None:
                continue
            if isinstance(normalized, list):
                hidden_inputs.extend(
                    FTInput(type="hidden", name=str(key), value=item) for item in normalized
                )
            else:
                hidden_inputs.append(FTInput(type="hidden", name=str(key), value=normalized))

    button = Button(
        label,
        variant=c_variant,
        outline=c_outline,
        icon=icon,
        type="submit",
        **attrs,
    )

    return FTForm(
        *hidden_inputs,
        button,
        method="post",
        action=endpoint,
    )