Guides

Arguments

More often than not, a component takes one or more arguments to render.

Every argument must be declared at the beginning of the component with {#def arg1, arg2, ... #}.

{#def action, method="post", multipart=False #}

<form method="{{ method }}" action="{{ action }}"
  {%- if multipart %} enctype="multipart/form-data"{% endif %}
>
  {{ content }}
</form>

In this example, the component takes three arguments: "action", "method", and "multipart". The last two have default values, so they are optional, but the first one doesn't. That means it must be passed a value when rendering the component.

The syntax is exactly like how you declare the arguments of a Python function (in fact, it's parsed by the same code), so it can even include type comments, although they are not used by JinjaX (yet!).

{#def
  data: dict[str, str],
  method: str = "post",
  multipart: bool = False
#}
...

Passing Arguments 

There are two types of arguments: strings and expressions.

String 

Strings are passed like regular HTML attributes:

<Form action="/new" method="PATCH"> ... </Form>

<Alert message="Profile updated" />

<Card title="Hello world" type="big"> ... </Card>

Expressions 

There are two different but equivalent ways to pass non-string arguments:

"Jinja-like", where you use double curly braces instead of quotes:

Jinja-like
<Example
    columns={{ 2 }}
    tabbed={{ False }}
    panels={{ {'one': 'lorem', 'two': 'ipsum'} }}
    class={{ 'bg-' + color }}
/>

... and "Vue-like", where you keep using quotes, but prefix the name of the attribute with a colon:

Vue-like
<Example
    :columns="2"
    :tabbed="False"
    :panels="{'one': 'lorem', 'two': 'ipsum'}"
    :class="'bg-' + color"
/>

With Content 

There is always an extra implicit argument: the content inside the component. Read more about it in the next section.

Extra Arguments 

If you pass arguments not declared in a component, those are not discarded but rather collected in an attrs object.

You then call attrs.render() to render the received arguments as HTML attributes.

For example, this component:

Card.jinja
{#def title #}
<div {{ attrs.render() }}>
  <h1>{{ title }}</h1>
  {{ content }}
</div>

Called as:

<Card title="Products" class="mb-10" open>bla</Card>

Will be rendered as:

<div class="mb-10" open>
  <h1>Products</h1>
  bla
</div>

You can add or remove arguments before rendering them using the other methods of the attrs object. For example:

{#def title #}
{% do attrs.set(id="mycard") -%}

<div {{ attrs.render() }}>
  <h1>{{ title }}</h1>
  {{ content }}
</div>

Or directly in the attrs.render() call:

{#def title #}

<div {{ attrs.render(id="mycard") }}>
  <h1>{{ title }}</h1>
  {{ content }}
</div>

attrs Methods 

.render(name=value, ...) 

Renders the attributes and properties as a string.

Any arguments you use with this function are merged with the existing attributes/properties by the same rules as the HTMLAttrs.set() function:

  • Pass a name and a value to set an attribute (e.g. type="text")
  • Use True as a value to set a property (e.g. disabled)
  • Use False to remove an attribute or property
  • The existing attribute/property is overwritten except if it is class. The new classes are appended to the old ones instead of replacing them.
  • The underscores in the names will be translated automatically to dashes, so aria_selected becomes the attribute aria-selected.

To provide consistent output, the attributes and properties are sorted by name and rendered like this: <sorted attributes> + <sorted properties>.

<Example class="ipsum" width="42" data-good />
<div {{ attrs.render() }}>
<!-- <div class="ipsum" width="42" data-good> -->

<div {{ attrs.render(class="abc", data_good=False, tabindex=0) }}>
<!-- <div class="abc ipsum" width="42" tabindex="0"> -->

You must pass them as the special argument _attrs.

{#--- WRONG 😵 ---#}
<MyButton {{ attrs.render() }} />

{#--- GOOD 👍 ---#}
<MyButton _attrs={{ attrs }} />
<MyButton :_attrs="attrs" /> 

.set(name=value, ...) 

Sets an attribute or property

  • Pass a name and a value to set an attribute (e.g. type="text")
  • Use True as a value to set a property (e.g. disabled)
  • Use False to remove an attribute or property
  • If the attribute is "class", the new classes are appended to the old ones (if not repeated) instead of replacing them.
  • The underscores in the names will be translated automatically to dashes, so aria_selected becomes the attribute aria-selected.
Adding attributes/properties
{% do attrs.set(
  id="loremipsum",
  disabled=True,
  data_test="foobar",
  class="m-2 p-4",
) %}
Removing attributes/properties
{% do attrs.set(
  title=False,
  disabled=False,
  data_test=False,
  class=False,
) %}

.setdefault(name=value, ...) 

Adds an attribute, but only if it's not already present.

The underscores in the names will be translated automatically to dashes, so aria_selected becomes the attribute aria-selected.

{% do attrs.setdefault(
    aria_label="Products"
) %}

.add_class(name1, name2, ...) 

Adds one or more classes to the list of classes, if not already present.

{% do attrs.add_class("hidden") %}
{% do attrs.add_class("active", "animated") %}

.remove_class(name1, name2, ...) 

Removes one or more classes from the list of classes.

{% do attrs.remove_class("hidden") %}
{% do attrs.remove_class("active", "animated") %}

.get(name, default=None) 

Returns the value of the attribute or property, or the default value if it doesn't exist.

{%- set role = attrs.get("role", "tab") %}