.. _custom_components: #################################### Building Custom Frontend Components #################################### .. index:: single: custom frontend components .. versionadded:: 2.0 Custom frontend components are a powerful tool for content editors, allowing them to build pages without needing in-depth knowledge of design, HTML, or nested structures. Editors can simply add content to pre-defined components, creating visually cohesive pages with ease. When working with `Tailwind CSS `_, for example, you either create your custom frontend components or customize components from providers, e.g. `Tailwind UI `_, `Flowbite `_, or the community `Tailwind Components `_. With django CMS you make your components available to the content editors to simply add them to a page by a click **and** frontend developers for use in templates from a single source. Custom frontend components are more versatile than template components, but require some minimal Python coding. Technically, you create a custom frontend component by declaring its change form and rendering template. Installation ============ Install ``djangocms-frontend`` and add it to your project as described here: :ref:`built_in_components`. If you do not use the built-in components, you do not need to add them to your ``INSTALLED_APPS``. .. code-block:: python INSTALLED_APPS = [ 'easy_thumbnails', 'djangocms_link', # Required if djangocms_frontend.contrib.link is used # Main frontend app - pre-built components not needed 'djangocms_frontend', ] Adding Styles and JavaScript ============================ When building template components, you will need to provide your custom CSS files either by adding them to the base templates to load on every page, or by adding a django-sekizai block to each component. Hero component example ====================== ``djangocms-frontend`` will look for custom frontend components in the **``cms_components`` module in any of your apps**. This way you can either keep components together in one theme app, or keep them with where they are used in different custom apps. Directory Structure ------------------- Let's go through this by creating a theme app:: python manage.py startapp theme Custom frontend components live in the ``cms_components`` module of any of your apps. Ensure your app has the following structure:: theme/ cms_components.py migrations/ models.py templates/ theme/ hero.html views.py admin.py Creating two Custom Frontend Components --------------------------------------- Add a ``cms_components.py`` file to the ``theme`` app (see structure above): .. code-block:: python # theme/cms_components.py from djangocms_link.fields import LinkFormField from djangocms_frontend.component_base import CMSFrontendComponent from djangocms_frontend.component_pool import components from djangocms_frontend.contrib.image.fields import ImageFormField @components.register class MyHeroComponent(CMSFrontendComponent): class Meta: # declare plugin properties name = "My Hero Component" # Name displayed in the CMS admin interface render_template = "theme/hero.html" # Template used to render the component allow_children = True # Allow child plugins inside this component mixins = ["Background"] # Add background styling options # for more complex components, you can add fieldsets # Declare fields for the component title = forms.CharField(required=True) slogan = forms.CharField(required=True, widget=forms.Textarea) hero_image = ImageFormField(required=True) def get_short_description(self): return self.title # Display the title in the structure board @components.register class MyButton(CMSFrontendComponent): class Meta: name = "Button" render_template = "components/button.html" allow_children = False text = forms.CharField(required=True) link = LinkFormField() def get_short_description(self): return self.text The templates could be, for example: .. code-block:: django {% load cms_tags frontend sekizai_tags %}

{{ instance.title }}

{{ instance.message }}

{% childplugins instance %} Get started Speak to Sales {% endchildplugins %}
{% addtoblock "js" %}{% endaddtoblock %} .. code-block:: django {% load djangocms_link_tags %} {{ instance.text }} As always, django CMS manages styling and JavaScript dependencies with django-sekizai. In this example, we add the Tailwind CSS CDN to the ``js`` block. .. note:: The component instance is available in the template as ``instance``. This is a proxy model of the ``FrontendUIItem`` model, which is a subclass of Django's ``Model`` class. The instance has all the fields declared in the component class. Additionally, if the component does not have a field called ``instance``, the fields themselves are available directly in the template. Both ways are equivalent:: {{ instance.title }} {{ title }} {{ instance.slogan }} {{ slogan }} Limitations of custom frontend components ========================================= Custom frontend components are a powerful tool for developers, but they have a limitations: **Limited Python code**: Custom components are (indirect) subclasses of Django's ``AdminForm`` class and can contain Python code to modify the behavior of a form. You cannot directly add Python code to the resulting plugin class with the exception of ``get_render_template()``. Similarly, you cannot add Python code the model class, in this case with the exception of ``get_short_description()``. Conclusion ========== In this tutorial, we explored how to create custom frontend components. These components empower developers to provide visually appealing components to content editors with minimal coding. By following the steps outlined above, you can: - Create a theme app to house your custom components. - Define components using the `CMSFrontendComponent` class. - Leverage templates to control the visual presentation of your components. - Register and manage your components seamlessly within django CMS. .. note:: Components will create migrations since they use proxy models of ``djangocms-frontend``'s ``FrontendUIItem`` model which are necessary, for example, to manage permissions. Those migrations will be added to the app containing the ``cms_component.py`` file.