cotton
for

Components

Components are reusable pieces of view template. They can contain native Django template syntax and can be used inside standard Django templates.

A minimal example:

cotton/my_component.html
{{ slot }}
my_view.html
<c-my-component>
    <p>Some content</p>
</c-my-component>
preview

Some content

The {{ slot }} variable will contain all of the content provided between the opening and closing tag of the current component as defined in the parent.

Attributes

Components are highly configurable. One way to control the content and behaviour of a component is through attributes.

cotton/weather.html
<p>It's {{ temperature }}<sup>{{ unit }}</sup> and the condition is {{ condition }}.</p>
<c-weather temperature="23" unit="c" condition="windy"></c-weather>
preview
It's 23c and the condition is windy.

Passing template variables by reference

Sometimes you'll want to pass a variable from the parent's context 'as is' for the child component to perform what it wants.

To pass data by reference, prepend the attribute with a " : ".

view.html
<c-weather :today="today"></c-weather>
cotton/weather.html
<p>It's {{ today.temperature }}<sup>{{ today.unit }}</sup> and the condition is {{ today.condition }}.</p>

Named slots

There are occasions when you will need to pass blocks of HTML or dynamic content. In these cases, we can reach to named slots .

Named slots are defined with the <c-slot name="...">...</c-slot> tag. The content is passed to the component like a standard template variable.

They allow you to define mixed markup, HTML and Django native tags and the rendered block will be provided as a template variable to the child component.

Adopting the nested HTML approach here keeps readability and integrates well with how editors already treat html-like tags and patterns.

After writing a couple of components like this, you will notice the fluidity of this approach.

cotton/weather_card.html
<div class="flex ...">
    <h2>{{ day }}:</h2> {{ icon }} {{ label }}
</div>
view.html
<c-weather-card day="Tuesday">
    <c-slot name="icon">
        <svg>...</svg>
    </c-slot>

    <c-slot name="label">
        <h2 class="text-yellow-500">Sunny</h2>
    </c-slot>
</c-weather-card>
preview

Tuesday:

Sunny

Pass all attributes with {{ attrs }}

It's sometimes useful to be able to reflect all attributes provided in the parent down to an HTML element in the component. This is particularly powerful when you are building form inputs.

cotton/input.html
<input type="text" class="border ..." {{ attrs }} />
form_view.html
<c-input name="first_name" placeholder="First name" />
<c-input name="last_name" placeholder="Last name" value="Smith" readonly  />
preview

Boolean attributes

Sometimes you just want to pass a simple boolean to a component. Cotton supports providing the attribute name without a value which will provide a boolean True to the component.

cotton/input.html
<input type="text" {{ attrs }} />

{% if required is True %}
    <span class="text-red-500">*</span>
{% endif %}
form_view.html
<c-input name="telephone" required />
preview
*

Using template expressions in attributes

Cotton allows you to include template variables and expressions inside attributes.

<c-weather temperature="{{ temperature|floatformat:0 }}"
           unit="{{ unit|default:'c' }}"
           condition="very {% get_intensity %}"
/>

Pass basic python data types

Using the ':' to prefix an attribute tells Cotton we're passing a dynamic type down. We already know we can use this to send a variable, but you can also send basic python types, namely:

  • Integers and Floats
  • None
  • True and False
  • Lists
  • Dictionaries

This benefits a number of use-cases, for example if you have a select component that you want to provide some value:

cotton/select.html
<select {{ attrs }}>
    {% for option in options %}
        <option value="{{ option }}">{{ option }}</option>
    {% endfor %}
</select>
question_view.html
<c-select name="q1" :options="['yes', 'no', 'maybe']" />
preview
Do you like carrots?

This approach can also be utilised by in-component vars in the c-vars tag:

cotton/search.html
<c-vars :config="{'category': 'fruit', 'limit': 10}" />

<div>
    Current category: {{ config.category }}
    Current limit: {{ config.limit }}
    ...
</div>

This example shows we can use c-vars to provide a default to an optional dictionary variable `config` from the parent.

Vars

Vars are defined using a <c-vars /> tag at the top of a component file. It can contain numerous key="value" pairs. It can also be a single key without a default value. Specifying an attribute as a 'var' will remove the item from {{ attrs }}.

<c-vars /> gives attributes default values

You may design a component that will often have a default behaviour and rarely needs overriding. In this case, you may opt to give a default value to your component.

cotton/alert.html
<c-vars type="success" />

<div class="{% if type == 'success' %} .. {% elif type == 'danger' %} .. {% endif %}">
    {{ slot }}
</div>
form_view.html
<c-alert>All good!</c-alert>
<c-alert type="danger">Oh no!</c-alert>
preview
All good!
Oh no!

Vars are excluded from {{ attrs }}

Keys defined in <c-vars /> will not be included in {{ attrs }}. This is useful when some of the properties you pass down to a component are for configuration purposes only and not intended as attributes.

cotton/input_group.html
<c-vars label errors />

<label>{{ label }}</label>

<input type="text" class="border ..." {{ attrs }} />

{% if errors %}
    {% for error in errors %}
        {{ error }}
    {% endfor %}
{% endif %}
form_view.html
<c-input-group label="First name" placeholder="First name" :errors="errors.first_name" />
<c-input-group label="Last name" placeholder="Last name" :errors="errors.last_name" />
preview



Last name is required

Dynamic Components

There can be times where components need to be included dynamically. For these cases we can reach for a special <c-component> tag with an is attribute:

cotton/icon_list.html
{% for icon in icons %}
    <c-component is="icons.{{ icon }}" />
{% endfor %}

The is attribute is similar to other attributes so we have a number of possibilities to define it:

cotton/icon_list.html
<!-- as variable -->
<c-component :is="icon_name" />

<!-- as an expression -->
<c-component is="icon_{{ icon_name }}" />
back Quickstart
next Layouts