Django Cotton

repository·main·Indexed 22 days ago

https://github.com/wrabit/django-cotton

Django Cotton brings component-based design to Django templates, allowing developers to compose UIs in a modular and reusable way using HTML-like syntax. It supports slots, named slots, dynamic components via <c-component>, and the ability to pass complex Python data types (lists, dicts, booleans) as attributes. It also provides a render_component() function for programmatically rendering components from views, which is particularly useful for HTMX-powered interfaces.

Tokens
9K
Snippets
36
Records
48
Agent score
78%

What's inside django-cotton

  1. Component Naming and Placement Basics

    main

    Django Cotton uses a specific convention for locating and calling components:

    • Placement: By default, components must be placed in the templates/cotton directory of your Django project.
    • Calling Components: Use kebab-case prefixed with c- in your templates (e.g., <c-my-component />).
    • Filenames: Component files should use snake_case (e.g., my_component.html).

    You can configure custom folders or filename patterns in your settings.

  2. Understand Cotton's Caching mechanism

    main

    Cotton uses a two-tier caching approach for performance:

    1. Compilation Cache: Cotton maintains its own cache to avoid re-processing component syntax if the file modification time hasn't changed.
    2. Django cached.Loader: For maximum performance, Cotton should be used with Django's cached.Loader. This caches fully parsed Template objects and avoids disk reads.

    Note: If you use Cotton's automatic configuration, the cached.Loader is applied automatically.

  3. Enable Smart Isolation for components

    main

    When COTTON_ISOLATE_BY_DEFAULT is set to True in your settings, components use Smart Isolation. This prevents accidental context leaks from the parent template (like {% with %} or {% for %} loops) while still allowing access to global context processors like request, user, and messages.

    To achieve total isolation (blocking even block context processors) for a specific component, use the only flag:

    <c-my-component only />
  4. Compare HTML-like vs Native Django Template Syntax

    main

    Cotton provides two ways to use components. The HTML-like Syntax is recommended because it offers better IDE support (autocompletion, formatting, and syntax highlighting). The Native Django Template Tag Syntax is available for developers who prefer the standard Django style.

    FeatureHTML-like SyntaxNative Template Syntax
    Component<c-button>...</c-button>{% cotton button %}...{% endcotton %}
    Self-closing<c-button />{% cotton button / %}
    Variables<c-vars title />{% cotton:vars title %}
    Named Slot<c-slot name="header">...</c-slot>{% cotton:slot header %}...{% endcotton:slot %}
  5. Create basic components with slots

    main

    A component is defined in a template file (e.g., cotton/button.html). Everything placed between the opening and closing tags of the component in the view is passed to the component as the {{ slot }} variable. This can include plain text, HTML, or Django template expressions.

    Component Definition:

    <!-- cotton/button.html -->
    <a href="/" class="...">{{ slot }}</a>

    Usage in View:

    <c-button>Contact</c-button>

    Output:

    <a href="/" class="...">Contact</a>
    <!-- cotton/button.html -->
    <a href="/" class="...">{{ slot }}</a>
    
    <!-- in view -->
    <c-button>Contact</c-button>
  6. Pass template variables and expressions as attributes

    main

    To pass a dynamic Django template variable or expression as an attribute, prepend the attribute name with a colon (:).

    • Template Variables: Use :attr="variable_name".
    • Complex Expressions: Use :attr="expression" for strings with spaces, lists, or dictionaries.
    • Template Expressions inside attributes: You can use standard Django template syntax inside the attribute value.

    Examples:

    • :user="user" (Variable)
    • :options="['yes', 'no']" (List)
    • icon="fa-{{ icon }}" (Expression)
    <c-bio-card :user="user" />
    
    <c-weather icon="fa-{{ icon }}" unit="{{ unit|default:'c' }}" />
  7. Merge or proxy attributes with `:attrs`

    main

    The :attrs attribute provides advanced control over attribute handling.

    Merge a dictionary of attributes

    Pass a dictionary (e.g., from your Django view context) to a component using :attrs="dict_name". These attributes are merged with any attributes passed directly and become available in the component's {{ attrs }} variable.

    # View context
    context = {'widget_attrs': {'placeholder': 'Name', 'size': '40'}}
    <c-input :attrs="widget_attrs" required />

    Proxy attributes to a nested component

    You can pass all attributes received by a wrapper component directly to a nested component by using <c-child :attrs="attrs">. This allows the child to receive the parent's attrs dictionary.

    Note: Attributes declared via <c-vars> in the parent are excluded from the attrs passed to the child.

    <c-input :attrs="widget_attrs" required />
    
    <c-outer-wrapper class="special-class">
        <c-inner-component :attrs="attrs">
            {{ slot }}
        </c-inner-component>
    </c-outer-wrapper>
  8. Define in-component variables with `<c-vars>`

    main

    Use <c-vars> to define variables that are scoped only to the component. This is useful for:

    1. Default attributes: Setting fallback values that can be overridden by the user.
      <c-vars theme="bg-purple-500" />
      <a class="{{ theme }}">{{ slot }}</a>
    2. Governing {{ attrs }}: Declaring a variable in <c-vars> prevents it from being included in the {{ attrs }} dictionary. This allows you to use specific component properties (like icon) without them leaking into the underlying HTML element (like an <input>).

    Example:

    <!-- cotton/input.html -->
    <c-vars icon />
    <img src="icons/{{ icon }}.png" />
    <input {{ attrs }} />
    <c-vars theme="bg-purple-500" />
    <c-vars icon />
  9. Use Subresource Integrity (SRI) with Highlight.js CDN

    main

    When loading Highlight.js via a CDN, you can use Subresource Integrity (SRI) to ensure the files have not been tampered with. This is done by adding the integrity attribute to your <script> tags. The attribute contains a cryptographic hash (digest) that the browser uses to verify the downloaded file against the expected version.

    To implement this, include the integrity attribute for the main library and any specific language grammars you are loading.

    <script
      src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"
      integrity="sha384-5xdYoZ0Lt6Jw8GFfRP91J0jaOVUq7DGI1J5wIyNi0D+eHVdfUwHR4gW6kPsw489E"></script>
    <!-- including any other grammars you might need to load -->
    <script
      src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/go.min.js"
      integrity="sha384-HdearVH8cyfzwBIQOjL/6dSEmZxQ5rJRezN7spps8E7iu+R6utS8c2ab0AgBNFfH"></script>
  10. Use Named Slots to pass HTML content

    main

    To pass complex HTML blocks or template expressions into a component, use the <c-slot> tag. This allows you to designate specific areas within your component template to receive content.

    Example:

    <c-my-header>
        <c-slot name="icon">
            <svg>...</svg>
        </c-slot>
    </c-my-header>