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, and onclick 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 (like div) should be changed to class. 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