Components are reusable pieces of view template. They can contain native Django template syntax and can be used inside standard Django templates.
The {{ slot }}
variable captures all content passed between a component's opening and closing tags.
<div class="box">
{{ slot }}
</div>
Used in a parent template:
<c-box>
<p>Some <strong>content</strong></p>
</c-box>
We can further customize components with attribute, which allow you to pass specific data into the component as key-value pairs.
<p>It's {{ temperature }}<sup>{{ unit }}</sup> and the condition is {{ condition }}.</p>
<c-weather temperature="23" unit="{{ unit }}" condition="windy"></c-weather>
If we want to pass HTML instead of just a string (or another data type) into a component, we can pass them as named slots with the <c-slot name="...">...</c-slot>
syntax.
So as with normal attributes, you reference the slot content like normal variables, as in:
<div class="flex ...">
<h2>{{ day }}:</h2> {{ icon }} {{ label }}
</div>
<c-weather-card day="Tuesday">
<c-slot name="icon">
<img src="sunny-icon.png" alt="Sunny">
</c-slot>
<c-slot name="label">
<div class="yellow">Sunny</div>
</c-slot>
</c-weather-card>
COTTON_SNAKE_CASED_NAMES
to False
in your settings.py, more.
We saw how by default, all attributes that we pass to a component are treated as strings. If we want to pass HTML, we can use named slots. But what if we want to pass another data type like a template variable, boolean, integer, float, dictionary, list, dictionary?
Sometimes you'll want to pass a variable from the parent's context 'as is' for the child component to perform what it wants.
<!--
context = { 'today': Weather.objects.get(...) }
-->
<c-weather :today="today"></c-weather>
<p>It's {{ today.temperature }}<sup>{{ today.unit }}</sup> and the condition is {{ today.condition }}.</p>
<c-mycomp :prop="1" />
<!-- {% prop == 1 %} -->
<c-mycomp :prop="None" />
<!-- {% prop is None %} -->
<c-mycomp :items="['item1','item2','item3']" />
<!-- {% for item in items %} -->
<c-mycomp :mydict="{'name': 'Thom', 'products': [1,2]}" />
<!-- {{ mydict.name }}, {{ mydict.products }} -->
<c-mycomp :product="product" />
<!-- {{ product.title }} -->
<c-mycomp :slides="['{{ image1 }}', '{{ image2 }}']" />
<!-- {% for images in slides %} -->
<c-mycomp :is_highlighted="{% if important %}True{% endif %}" />
<!-- {% is_valid is False %} -->
A quick example of this is a select component that you want to fill with options:
<c-select :options="['no', 'yes', 'maybe']" />
<select>
{% for option in options %}
<option value="{{ option }}">{{ option }}</option>
{% endfor %}
</select>
Sometimes it's useful to be able to reflect all attributes provided in the parent on to an HTML element in the component. This is particularly powerful when you are building form inputs.
<c-input name="first_name" placeholder="First name" />
<c-input name="last_name" placeholder="Last name" value="Smith" readonly />
<input type="text" {{ attrs }} />
<!-- html output
<input type="text" name="first_name" placeholder="First name" />
<input type="text" name="last_name" placeholder="Last name" value="Smith" readonly />
-->
<c-vars />
The <c-vars />
tag simplifies component design by allowing local variable definition, reducing the need for repetitive attribute declarations and maintaining backend state.
Place a single <c-vars />
at the top of a component to set key-value pairs that provide a default configuration.
In components with common defaults, <c-vars />
can pre-define attributes that rarely need overriding.
<c-vars type="success" />
<div class="{% if type == 'success' %} .. {% elif type == 'danger' %} .. {% endif %}">
{{ slot }}
</div>
<c-alert>All good!</c-alert>
<c-alert type="danger">Oh no!</c-alert>
Keys in <c-vars />
are omitted from {{ attrs }}
, making them ideal for configuration attributes that shouldn't appear in HTML attributes.
<c-vars label errors />
<label>{{ label }}</label>
<input type="text" class="border ..." {{ attrs }} />
{% if errors %}
{% for error in errors %}
{{ error }}
{% endfor %}
{% endif %}
<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" />
By specifying label
and errors
keys in <c-vars />
, these attributes won’t be included in {{ attrs }}
, allowing you to control attributes that are designed for component configuration and those intended as 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.
<input type="text" {{ attrs }} />
{% if required is True %}
<span class="text-red-500">*</span>
{% endif %}
<c-input name="telephone" required />
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:
{% 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:
<!-- as variable -->
<c-component :is="icon_name" />
<!-- as an expression -->
<c-component is="icon_{{ icon_name }}" />
Similar to Django's {% include %}
tag you can add an "only
" attribute which will prevent the component from inheriting the parent's context.
{{ slot }}
- Default content injection.:
Dynamic Attributes - Pass variables and other data types other than strings.{{ attrs }}
- Prints attributes as HTML attributes.<c-vars />
- Set default values and other component state.True
<c-component :is="my_variable" />