Components#

Unicorn uses the term “component” to refer to a set of interactive functionality. A component consists of a Python view class which provides the backend code and a Django HTML template.

Create a component#

The easiest way to create your first component is to run the startunicorn Django management command after Unicorn is installed.

The first argument to startunicorn is the Django app to add your component to. Every argument after the first is the name of a component to create.

# Create `hello-world` and `hello-magic` components in `myapp`
python manage.py startunicorn myapp hello-world hello-magic

That would create a file structure like the following:

myapp/
    components/
        __init__.py
        hello_world.py
        hello_magic.py
    templates/
        myapp/
            hello-world.html
            hello-magic.html

Warning

Make sure that the app name specified is in the INSTALLED_APPS list in your Django settings file (normally settings.py).

Use a component#

Components usually reside in a regular Django template (unless it is a direct view). The component is “included” (similar to the include templatetag) with a unicorn templatetag.

<!-- index.html -->
{% load unicorn %}

<!-- The CSRF token is required by Unicorn to prevent cross-site scripting attacks -->
{% csrf_token %}

<!--
Include the `hello-world.html` HTML template with data provided by the `hello_world.HelloWorldView` Python view
-->
{% unicorn 'hello-world' %}

A basic component#

An example component consists of the following Python view class and HTML template.

# hello_world.py
from django_unicorn.components import UnicornView

class HelloWorldView(UnicornView):
    name = "World"
<!-- hello-world.html -->
<div>
  <input unicorn:model="name" type="text" id="text" /><br />
  Hello {{ name|title }}
</div>

unicorn:model is the magic that ties the input to the backend component. When this component renders, the input element will include a value of “World” because that is the value of the name field in the view. It will read “Hello World” below the input element. When a user types “universe” into the input element, the component is re-rendered with the new name – the text will now be “Hello Universe”.

Note

By default unicorn:model updates are triggered by listening to input events on the element. To listen for the blur event instead, use the lazy modifier.

Pass data to a component#

args and kwargs can be passed into the unicorn templatetag from the outer template. They will be available in the component component_args and component_kwargs instance methods respectively.

<!-- index.html -->
{% load unicorn %}
{% csrf_token %}

{% unicorn 'hello-world' "Hello" name="World" %}
# hello_world.py
from django_unicorn.components import UnicornView

class HelloWorldView(UnicornView):
    def mount(self):
        arg = self.component_args[0]
        kwarg = self.component_kwargs["name"]

        assert f"{arg} {kwarg}" == "Hello World"

Any variable available in the template context can be passed in as an argument.

<!-- index.html -->
{% load unicorn %}
{% csrf_token %}

<!-- Access nested data from the dictionary in the template context and set on the `name` kwarg -->
{% unicorn 'hello-world' name=hello.world.name %}
# views.py
from django.shortcuts import render

def index(request):
    context = {"hello": {"world": {"name": "Galaxy"}}}

    return render(request, "index.html", context)

The component view which can use the name kwarg.

# hello_world.py
from django_unicorn.components import UnicornView

class HelloWorldView(UnicornView):
    def mount(self):
        kwarg = self.component_kwargs["name"]

        assert kwarg == "Galaxy"

Component key#

If there are multiple of the same components on the page, a key kwarg can be passed into the template. For example, {% unicorn 'hello-world' key='helloWorldKey' %}. This is useful when a unique reference to a component is required, but it is optional.

Component sub-folders#

Components can be nested in sub-folders.

myapp/
    components/
        __init__.py
        hello/
            __init__.py
            world.py
    templates/
        myapp/
            hello/
                world.html

An example of how the above component would be included in a template.

<!-- index.html -->
{% load unicorn %}
{% csrf_token %}

{% unicorn 'hello.world' %}