.. _components-with-slots: #################################### Creating Components with Slots #################################### .. index:: single: Components with slots single: Slots .. versionadded:: 2.0 Slots allow you to define specific regions within a component where content editors can add child plugins. This is useful when you want to control the structure of a component while allowing flexibility in certain areas. What are slots? =============== Slots are predefined placeholders in a component that: - Automatically create child plugin types for each slot - Restrict where child plugins can be added - Provide fallback content when a slot is empty - Are automatically created when a component instance is saved Defining slots ============== To define slots in your component, add a ``slots`` attribute to the component's ``Meta`` class: .. code-block:: python from django import forms from djangocms_frontend.component_base import CMSFrontendComponent, Slot from djangocms_frontend.component_pool import components from djangocms_frontend.contrib.image.fields import ImageFormField @components.register class MyHero(CMSFrontendComponent): class Meta: name = "My Hero Component" render_template = "hero.html" slots = ( ("title", "Title"), # (slot_name, verbose_name) ("slot", "Slot"), ) title = forms.CharField(required=True, initial="my title") slogan = forms.CharField( required=True, initial="django CMS' plugins are great components", widget=forms.Textarea ) image = ImageFormField(required=True) def get_short_description(self): return self.title **Slot definition formats:** Simple tuple format:: slots = ( ("slot_name", "Verbose Name"), ("buttons", "Buttons"), ) Using the Slot class for advanced options:: from djangocms_frontend.component_base import Slot slots = ( Slot("slot_name", "Verbose Name", allow_children=False), Slot("buttons", "Buttons", **additional_plugin_kwargs), ) Using slots in templates ========================= In your render template, use the ``{% childplugins %}`` template tag to render slot content: .. code-block:: django {% load cms_tags frontend sekizai_tags %}

{% childplugins instance "title" %} {{ instance.title }} {% endchildplugins %}

{% childplugins instance "slogan" %} {{ instance.slogan }} {% endchildplugins %}

{% childplugins instance "slot" %} Get started {% endchildplugins %}
The content between ``{% childplugins %}`` and ``{% endchildplugins %}`` serves as fallback content that will be displayed when the slot has no child plugins. How slots work ============== When you define slots in a component: 1. **Child plugin classes are created automatically**: For a component named ``MyHero`` with a slot named ``title``, a plugin class ``MyHeroTitlePlugin`` is automatically generated. 2. **Parent-child relationships are enforced**: Slot plugins can only be added as children of their parent component. 3. **Auto-creation on save**: When a new component instance is created, all slot plugins are automatically added to it (see ``save_model`` in :class:`~djangocms_frontend.component_base.CMSFrontendComponent`). 4. **allow_children is set automatically**: When slots are defined, ``allow_children`` is automatically set to ``True`` on the component plugin. Example with multiple slots ============================ Here's a more complex example with multiple slots: .. code-block:: python @components.register class HeroWithSlots(CMSFrontendComponent): class Meta: name = "Hero with Slots" render_template = "hero_slots.html" slots = ( ("title", "Title Slot"), ("subtitle", "Subtitle Slot"), ("buttons", "Button Area"), ("footer", "Footer Content"), ) background_color = forms.CharField(required=False) hero_image = ImageFormField(required=True) Template: .. code-block:: django {% load cms_tags %}
{% childplugins instance "title" %}

Default Title

{% endchildplugins %} {% childplugins instance "subtitle" %}

Default subtitle text

{% endchildplugins %} {% childplugins instance "buttons" %} {% endchildplugins %}
Advanced: Manual slot iteration with get_slot ============================================== For more control over slot rendering, you can use the ``get_slot`` template filter to manually iterate over slot plugins: .. code-block:: django {% load cms_tags frontend %}
{% for plugin in instance|get_slot:"buttons" %}
{% render_plugin plugin %}
{% empty %}

No buttons added yet

{% endfor %}
The ``get_slot`` filter takes the slot name as an argument and returns a generator of child plugins in that slot. This is useful when you need to: - Add custom wrapper HTML around each plugin in a slot - Apply specific classes or attributes to individual slot items - Implement complex layouts that require more control than ``{% childplugins %}`` provides - Handle empty slots with custom logic using ``{% empty %}`` **Comparison:** Using ``{% childplugins %}`` (automatic rendering with fallback): .. code-block:: django {% childplugins instance "buttons" %} {% endchildplugins %} Using ``get_slot`` filter (manual control): .. code-block:: django {% for plugin in instance|get_slot:"buttons" %}
{% render_plugin plugin %}
{% empty %} {% endfor %} See also :py:func:`~djangocms_frontend.templatetags.frontend.get_slot` in the reference documentation.