Bluefox Stack

Jinja2 macros
for the Bluefox Stack

Parameterized component templates, Pico CSS theming, and a built-in showcase. Import a macro, pass your data, get consistent UI across every Bluefox app.

Quick start
01

Install the package

$ uv add bluefox-components
02

Register templates and static assets

main.py
from bluefox_core import BluefoxSettings, create_bluefox_app
from bluefox_components import setup_components

settings = BluefoxSettings()
app = create_bluefox_app(settings)
setup_components(app)
03

Use macros in your templates

templates/login.html
{% extends "bfx/base.html" %}
{% from "bfx/button.html" import button %}
{% from "bfx/input.html" import input %}

{% block content %}
<form method="post">
  {{ input(name="email", type="email", label="Email") }}
  {{ input(name="password", type="password", label="Password") }}
  {{ button("Sign in") }}
</form>
{% endblock %}
What you get

Jinja2 macros

Buttons, inputs, selects, cards, alerts, modals, tables, and more. Each macro has explicit parameters for the common case and an attrs dict for escape hatches.

Pico CSS theming

One CSS file overrides Pico's custom properties with the Bluefox palette. DM Sans typography, warm backgrounds, consistent borders. Light and dark modes included.

HTMX-ready

Every macro accepts arbitrary HTML attributes via the attrs parameter. Pass hx-post, hx-target, or any attribute without the macro knowing about HTMX.

Base layout

Extend bfx/base.html for a complete page with nav, main content area, and footer. Override blocks to customize any section.

Component showcase

A production route at /components displays every macro with live examples and copy-paste code. Living documentation for your team.

Zero build step

Pure Jinja2 templates and CSS custom properties. No Tailwind, no bundler, no compilation. Install the package, call one function, start using macros.

Macro examples

Macros emit semantic HTML that Pico already styles. A card is an <article>, a form group is a <label> wrapping an input. Minimal custom classes.

templates/dashboard.html
{% from "bfx/button.html" import button %}
{% from "bfx/card.html" import card %}
{% from "bfx/alert.html" import alert %}

{# Simple button #}
{{ button("Save") }}

{# Button with HTMX #}
{{ button("Delete", variant="outline",
         attrs={"hx-delete": "/items/1"}) }}

{# Card with content slot #}
{% call card(title="Users") %}
  <p>42 active users</p>
{% endcall %}

{# Flash message #}
{{ alert("Changes saved.", variant="success") }}