Hydra Cookbook#

Components#

Hydra uses the Jinja template language for its html templates (.jinja files).

Jinja provides a control structure called a macro that is comparable a function and is used by Hydra to create frontend components.

An example of a macro/component definition is below:

templates/components/link.jinja#
{% macro link(url, text='', target='') %}
    <a href="{{ url }}"
    target="{{ target }}"
    class="text-blue-500; hover:text-blue-700; underline">{{ text }}</a>
{% endmacro %}

To use this macro elsewhere in the project, you would call it like so:

{{ link(url="https://www.example.com", target="_blank", text="example website") }}

For more information on Jinja macros see here.

Forms#

Hydra makes it easy to customize Django forms to suit your needs.

Custom Layouts#

When including a form in a template, you can customize the layout of the form by setting a template_name in the form that is provided to your view.

By default Hydra does this with several forms and by convention the names of these templates have _form appended to the name of the parent template (e.g. for login.jinja, the form template is login_form.jinja).

In this form template you can adjust what django widgets are used for each field within the form. For example:

templates/account/login_form.jinja#
{% from 'forms/field.jinja' import field as f %}
{% from 'forms/checkbox.jinja' import checkbox %}
<div class="form-wrapper justify-between">
    {{ errors }}
    {% for field, errors in fields %}
        {% if field.name == 'remember' %}
            {{ checkbox(field) }}  {# remember should be a checkbox macro #}
        {% else %}
            {{ f(field, errors) }}  {# any other field should use Hydra's field macro #}
        {% endif %}
    {% endfor %}
    <a href="{{ url("account_reset_password") }}"
    hx-select='#account-box'
    class="link">Forgot your password?</a>
    {% for field in hidden_fields %}{{ field }}{% endfor %}
</div>

For more information about looping through form fields see here.

Django Widget to Jinja Macro#

Hydra creates several mappings from Django’s built in form widgets to its own, custom jinja macros. This is done through template overrides within templates/django/forms/widgets which are mapped to macros in templates/forms.

You can also extend these mappings as necessary in your own project. An example of how to do is shown below using the input widget.

Example#

The jinja macro is defined in templates/forms

templates/forms/input.jinja#
{% from 'components/util.jinja' import attributes %} {# helper macro for html attributes #}

{% macro input(type="text", name=none, value=none, model="input", color='primary', attrs={}, left_icon='', right_icon='') %}
    {% set disabled, readonly = attrs.disabled, attrs.readonly %}
    {% set noedit = disabled or readonly %}
    <input
        {% do attrs.update({"type": type, "name": name, "value": value}) %}
        {{ attributes(attrs) }}
    />
{% endmacro %}

{# takes a django widget and calls our input macro with the appropriate args #}
{% macro widget_to_input(widget) %}
    {{ input(type=widget.type, name=widget.name, value=widget.value, model=widget.attrs.id, attrs=widget.attrs )}}
{% endmacro %}

An html template for the widget to be overridden is added to templates/django/forms/widgets

templates/django/forms/widgets/input.html#
{% from 'forms/input.jinja' import widget_to_input %}

{{ widget_to_input(widget) }}

Warning

Some input widgets in Django admin reference the default input widget, which is overridden by a custom Hydra component. Hydra includes a legacy default input at templates/django/forms/widgets/default_input.html that we use when overriding any references to the original (see templates/admin/widgets/url.html for an example of this).

If, in the future, Django adds more widgets with this behavior you will need to backport Hydra’s changes to support them or implement an override yourself using the existing templates as an example.