Django-components provides a seamless integration with HTML fragments ([HTML over the wire](https://hotwired.dev/)), whether you're using HTMX, AlpineJS, or vanilla JavaScript. When you define a component that has extra JS or CSS, and you use django-components to render the fragment, django-components will: - Automatically load the associated JS and CSS - Ensure that JS is loaded and executed only once even if the fragment is inserted multiple times !!! info **What are HTML fragments and "HTML over the wire"?** It is one of the methods for updating the state in the browser UI upon user interaction. How it works is that: 1. User makes an action - clicks a button or submits a form 2. The action causes a request to be made from the client to the server. 3. Server processes the request (e.g. form submission), and responds with HTML of some part of the UI (e.g. a new entry in a table). 4. A library like HTMX, AlpineJS, or custom function inserts the new HTML into the correct place. ## Document and fragment types Components support two modes of rendering - As a "document" or as a "fragment". What's the difference? ### Document mode Document mode assumes that the rendered components will be embedded into the HTML of the initial page load. This means that: - The JS and CSS is embedded into the HTML as `
OLD
{% component_js_dependencies %} """ ``` ### 2. Define fragment HTML ```djc_py title="[root]/components/demo.py" class Frag(Component): def get(self, request): return self.render_to_response( # IMPORTANT: Don't forget `type="fragment"` type="fragment", ) template = """
123
""" js = """ document.querySelector('#frag-text').textContent = 'xxx'; """ css = """ .frag { background: blue; } """ ``` ### 3. Create view and URLs ```py title="[app]/urls.py" from django.urls import path from components.demo import MyPage, Frag urlpatterns = [ path("mypage/", MyPage.as_view()) path("mypage/frag", Frag.as_view()), ] ``` ## Example - AlpineJS ### 1. Define document HTML ```djc_py title="[root]/components/demo.py" from django_components import Component, types # HTML into which a fragment will be loaded using AlpineJS class MyPage(Component): def get(self, request): return self.render_to_response() template = """ {% load component_tags %} {% component_css_dependencies %}
OLD
{% component_js_dependencies %} """ ``` ### 2. Define fragment HTML ```djc_py title="[root]/components/demo.py" class Frag(Component): def get(self, request): # IMPORTANT: Don't forget `type="fragment"` return self.render_to_response( type="fragment", ) # NOTE: We wrap the actual fragment in a template tag with x-if="false" to prevent it # from being rendered until we have registered the component with AlpineJS. template = """ """ js = """ Alpine.data('frag', () => ({ fragVal: 'xxx', })); // Now that the component has been defined in AlpineJS, we can "activate" // all instances where we use the `x-data="frag"` directive. document.querySelectorAll('[data-name="frag"]').forEach((el) => { el.setAttribute('x-if', 'true'); }); """ css = """ .frag { background: blue; } """ ``` ### 3. Create view and URLs ```py title="[app]/urls.py" from django.urls import path from components.demo import MyPage, Frag urlpatterns = [ path("mypage/", MyPage.as_view()) path("mypage/frag", Frag.as_view()), ] ``` ## Example - Vanilla JS ### 1. Define document HTML ```djc_py title="[root]/components/demo.py" from django_components import Component, types # HTML into which a fragment will be loaded using JS class MyPage(Component): def get(self, request): return self.render_to_response() template = """ {% load component_tags %} {% component_css_dependencies %}
OLD
{% component_js_dependencies %} """ ``` ### 2. Define fragment HTML ```djc_py title="[root]/components/demo.py" class Frag(Component): def get(self, request): return self.render_to_response( # IMPORTANT: Don't forget `type="fragment"` type="fragment", ) template = """
123
""" js = """ document.querySelector('#frag-text').textContent = 'xxx'; """ css = """ .frag { background: blue; } """ ``` ### 3. Create view and URLs ```py title="[app]/urls.py" from django.urls import path from components.demo import MyPage, Frag urlpatterns = [ path("mypage/", MyPage.as_view()) path("mypage/frag", Frag.as_view()), ] ```