Django-components provides a seamless integration with HTML fragments with AJAX ([HTML over the wire](https://hotwired.dev/)), whether you're using jQuery, HTMX, AlpineJS, vanilla JavaScript, or other. If the fragment component has any JS or CSS, 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 strategies Components support different ["strategies"](../../advanced/rendering_js_css#dependencies-strategies) for rendering JS and CSS. Two of them are used to enable HTML fragments - ["document"](../../advanced/rendering_js_css#document) and ["fragment"](../../advanced/rendering_js_css#fragment). What's the difference? ### Document strategy Document strategy 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 %} """ class View: def get(self, request): return self.component_cls.render_to_response(request=request) ``` ### 2. Define fragment HTML The fragment to be inserted into the document. IMPORTANT: Don't forget to set `deps_strategy="fragment"` ```djc_py title="[root]/components/demo.py" class Frag(Component): template = """
123
""" js = """ document.querySelector('#frag-text').textContent = 'xxx'; """ css = """ .frag { background: blue; } """ class View: def get(self, request): return self.component_cls.render_to_response( request=request, # IMPORTANT: Don't forget `deps_strategy="fragment"` deps_strategy="fragment", ) ``` ### 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 This is the HTML into which a fragment will be loaded using AlpineJS. ```djc_py title="[root]/components/demo.py" from django_components import Component, types class MyPage(Component): template = """ {% load component_tags %} {% component_css_dependencies %}
OLD
{% component_js_dependencies %} """ class View: def get(self, request): return self.component_cls.render_to_response(request=request) ``` ### 2. Define fragment HTML The fragment to be inserted into the document. IMPORTANT: Don't forget to set `deps_strategy="fragment"` ```djc_py title="[root]/components/demo.py" class Frag(Component): # 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; } """ class View: def get(self, request): return self.component_cls.render_to_response( request=request, # IMPORTANT: Don't forget `deps_strategy="fragment"` deps_strategy="fragment", ) ``` ### 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 This is the HTML into which a fragment will be loaded using vanilla JS. ```djc_py title="[root]/components/demo.py" from django_components import Component, types class MyPage(Component): template = """ {% load component_tags %} {% component_css_dependencies %}
OLD
{% component_js_dependencies %} """ class View: def get(self, request): return self.component_cls.render_to_response(request=request) ``` ### 2. Define fragment HTML The fragment to be inserted into the document. IMPORTANT: Don't forget to set `deps_strategy="fragment"` ```djc_py title="[root]/components/demo.py" class Frag(Component): template = """
123
""" js = """ document.querySelector('#frag-text').textContent = 'xxx'; """ css = """ .frag { background: blue; } """ class View: def get(self, request): return self.component_cls.render_to_response( request=request, # IMPORTANT: Don't forget `deps_strategy="fragment"` deps_strategy="fragment", ) ``` ### 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()), ] ```