in it has not been
written plainly enough for a landing page.
#}
{% set features = [
("No build step",
"No package.json, no node_modules, no watcher. The stylesheet is compiled when fjkit is released, not when your app runs."),
("One colour knob",
"Every colour is a token. Rebranding is one file, and green still means done afterwards."),
("Mounts on your existing API",
"Every htmx endpoint answers curl with JSON. Same route, same handler, same return annotation."),
] %}
{% block content %}
{% call stack(8) %}
{% set intro %}
An integration of Jinja, Tailwind CSS and shadcn-style components, for FastAPI.
{% endset %}
{{ page_header("A Fast UI for FastAPI", intro) }}
{{ defs("The key features are:", features) }}
{# ============================================================== 01 #}
{% set i01 %}A back-end developer who needs a real interface and no front-end toolchain.{% endset %}
{% call lesson("who", "01", "Who it is for", i01) %}
{% call prose() %}
You already write FastAPI. You need navigation, dark mode, a filterable table and a form that
validates. This is for you.
If you are bringing React, Vue or Svelte, this is the wrong layer. That is a decision, not a
gap.
{% endcall %}
{{ defs("What it should cost you", [
("a first page", "navigation and dark mode in about twenty lines of Python, with no build step"),
("an admin screen", "list, filters, a create form and htmx updates in an afternoon. No CSS, no JavaScript."),
("a rebrand", "one stylesheet of token overrides, loaded after the kit's"),
("an upgrade", "a version bump. The stylesheet lives in the wheel, not in your repository."),
]) }}
{% endcall %}
{# ============================================================== 02 #}
{% set i02 %}One wheel, two runtime dependencies, and nothing for you to compile.{% endset %}
{% call lesson("box", "02", "What ships in the wheel", i02) %}
{% call grid(cols=2, gap=4) %}
{{ defs("Shipped in the package", [
("templates/ui/", "the macros: layout, buttons, data, forms, tables, tabs, navigation, sidebar, feedback, icons, and the document shell"),
("static/dist/fjkit-.css", "the compiled stylesheet, one per style pack. 234 KB raw, 23.9 KB gzip, under a 28 KB budget the build enforces. A page loads one."),
("static/vendor/", "htmx and Basecoat's JavaScript, pinned and served out of the package"),
("1,767 icons", "Lucide, inlined by name. No icon font, no sprite request, no runtime JS."),
]) }}
{{ defs("The whole surface you touch", [
("FjkitConfig, mount_fjkit", "the wiring, once per app"),
("@render", "name a template on the decorator; the handler returns data"),
("fjkit check", "the vocabulary gate. Run it in your CI."),
("fjkit eject", "the escape hatch: take one macro into your app and edit it"),
]) }}
{% endcall %}
{% call prose() %}
Requirements: Python 3.13 or newer, and two runtime dependencies โ FastAPI and Jinja2. Adding
a third needs an argument nobody has made yet.
{% endcall %}
{% endcall %}
{# ============================================================== 03 #}
{% set i03 %}Two pages. One shows you the wiring, the other shows you every macro.{% endset %}
{% call lesson("next", "03", "Where to go next", i03) %}
{% set n_learn %}how the kit is wired, what htmx sends, and the gate that fails a build{% endset %}
{% set n_components %}every macro, live, with the call that made it{% endset %}
{{ defs("On this site", [
("Learn", n_learn),
("Components", n_components),
]) }}
{% endcall %}
{% endcall %}
{% endblock %}