Components
Creating components with JinjaX
See the JinjaX guide for an overview of JinjaX, particularly the motivation for using components similar to other front end frameworks.
The components in this project follow the patterns described in the JinjaX docs, with a few additional patterns. The following overview describes the basic composition of a component.
Example Button
Component
Button
The Button component wraps options and behaviors for html buttons and provides variants for different styles, similar to the shadcn/ui version.
{#def
className: str = "",
variant: str = "default",
size: str = "default",
disabled: bool = False
#}
{% set baseclassName = "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-zinc-950 dark:focus-visible:ring-zinc-300" %}
{% set variantclassName = {
'default': 'bg-zinc-900 text-zinc-50 hover:bg-zinc-900/90 dark:bg-zinc-50 dark:text-zinc-900 dark:hover:bg-zinc-50/90',
'destructive': 'bg-red-500 text-zinc-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-zinc-50 dark:hover:bg-red-900/90',
'outline': 'border border-zinc-200 bg-white hover:bg-zinc-100 hover:text-zinc-900 dark:text-zinc-50 dark:border-zinc-700 dark:bg-zinc-950 dark:hover:bg-zinc-800 dark:hover:text-zinc-50',
'secondary': 'bg-zinc-100 text-zinc-900 hover:bg-zinc-100/80 dark:bg-zinc-800 dark:text-zinc-50 dark:hover:bg-zinc-800/80',
'ghost': 'hover:bg-zinc-100 hover:text-zinc-900 dark:hover:bg-zinc-800 dark:hover:text-zinc-50',
'link': 'text-zinc-900 underline-offset-4 hover:underline dark:text-zinc-50'
}[variant] %}
{% set sizeclassName = {
'default': 'h-10 px-4 py-2',
'sm': 'h-9 rounded-md px-3',
'lg': 'h-11 rounded-md px-8',
'icon': 'h-10 w-10'
}[size] %}
<button
class="{{ baseclassName }} {{ variantclassName }} {{ sizeclassName }} {{ className }}"
{% if disabled %}disabled{% endif %}
{{ attrs.render() }}
>
{{ content }}
</button>
You can see there are a lot of utility styles required to render a simple HTML button with styling.
Components
Every component has similar qualities. They each:
- Declare arguments in a block
{#def ... #}
at the top of the file. - Use regular Jinja syntax for conditionals, variables or other logic.
- Can use the variables passed within the component template.
- Have a special slot variable called
{{ content }}
to render nested components or content. - Can invoke extra arguments passed to the declaration via
{{ attrs.render() }}
- Can have extra utility styles passed to it via the
className
argument.
Arguments:
- Arguments can have default values.
- Arguments are passed via HTML attributes when a component is declared.
- Arguments can pass objects via the
:attrValue={{ object }}
notation, similar to vue (with a leading:
). Otherwise arguments are evaluated as Strings. See expressions in the JinaX docs.
Using components
Within a template or another component, declare the Button
with its html tags, passing attributes as needed.
Content inside the tags will be rendered inside the content
slot.
The Mail
component below renders an SVG icon from the Lucide icon set.
<Button variant="secondary">Secondary</Button>
<Button className="space-x-2">
<!-- include and svg icon -->
<MailIcon className="mr-2 h-4 w-4" invert="True" />
Login with Email
</Button>
<Button id="submitBtn" onclick="alert('Button Clicked!')">
Click Me
</Button>
- The
Button
component is inserted directly into the template without macros or includes. - Attribute like
id
,className
, andonclick
are set directly, and any additional attributes can be passed as needed.
Adding htmx
Htmx attributes can be added to components when they are declared to add htmx behaviors.
<Button
hx-get="/demo/button"
hx-target="this"
hx-swap="outerHTML"
type="button"
variant="outline"
>Click me</Button>
See the using htmx docs for further details.
shadcn/ui components
The components in this project follow patterns from shadcn/ui very closely, using identical names for each class (React) and template(JinjaX). In many cases, it's possible to copy/paste code using the react versions directly into templates. There are a few notable differences:
- JinjaX does not have the same semantics to refer to props from other components
- React code contaning
className
on regular html elements (likediv
) should be changed toclass
. Eg<div className="mt-0">
should be changed to<div class="mt-0">
so Tailwind will apply styles correctly. - Client side state needs to be implemented via Alpine.js
- Interactivity can be added via htmx