HTML-First ui.* Template Tags (Alongside React Tags)
Summary
Introduce a HTML-first template tag namespace for Alliance UI components: ui.* (for example {% ui.button %}), while keeping existing React-backed tags ({% Button %}) unchanged.
Background
Old template used Antd and we manually applied classes to HTML to mirror Antd styles so was consistent with React components. Was fragile to changes in Antd and also required knowledge of internals (e.g. what classes to apply), and broke when styling was rewritten in v5.
We introduced @allianceplatform/ui which focused first on React components, with the idea being we could then roll out Django HTML template versions in a library to avoid the issues described above. In the meantime we introduced template tags like {% Button %} that just rendered the React version under the hood.
Why
- Avoid unnecessary React/hydration for simple UI primitives.
- Keep visual parity with existing Alliance UI styles.
- Make things like HTMX integration easier
- Better UX; no flash of content when component first renders (avoided by SSR, but SSR has it's own cost)
Proposed Public Interface
-
Naming
- HTML-first tags:
{% ui.button %}, {% ui.button_group %}, etc.
- Existing React tags remain as-is:
{% Button %}, {% ButtonGroup %} etc.
- Alternatives:
{% ui 'button' %}, {% button %} or switch out implementation on {% Button %} (breaking change)
-
API Compatibility
ui.* tags should mirror React component props/defaults where practical.
- Invalid enum props should warn and fall back (not hard-fail templates).
-
Runtime Behavior
- Default is static HTML output.
- For components needing JS behavior, use a small attach runtime pattern:
- render
data-djid or similar on container
- inject
<script type="module"> and call attach(element)
-
Assets
- CSS and runtime resources are discoverable through existing bundler/resource mechanisms. Shipped bundle only includes styles used.
-
Exstensible
- Provide necessary primitives to make it easy for projects to provide own component tags
Scope
Initial scope would be those that lend themselves to no/low JS: buttons, tables, tabs etc. menubar has slightly higher JS requirement but a bigger payoff given it's used on every page for navigation, so would be part of initial scope.
HTMX
No immediate plans to adopt this, but this change would also enable server-rendered components to work naturally in HTMX flows without React boundaries.
e.g.: ui.table can support pagination/filter updates via hx-get/hx-swap while preserving Alliance UI styling
(this is me assuming a few things based on my understanding without having used HTMX)
Examples
{% load alliance_platform.ui %}
{% ui.button type="submit" variant="solid" color="primary" %}
Save changes
{% endui.button %}
{% load alliance_platform.ui %}
{% ui.button_group variant="outlined" size="sm" density="compact" %}
{% ui.button %}Day{% endui.button %}
{% ui.button %}Week{% endui.button %}
{% ui.button %}Month{% endui.button %}
{% endui.button_group %}
HTML-First
ui.*Template Tags (Alongside React Tags)Summary
Introduce a HTML-first template tag namespace for Alliance UI components:
ui.*(for example{% ui.button %}), while keeping existing React-backed tags ({% Button %}) unchanged.Background
Old template used Antd and we manually applied classes to HTML to mirror Antd styles so was consistent with React components. Was fragile to changes in Antd and also required knowledge of internals (e.g. what classes to apply), and broke when styling was rewritten in v5.
We introduced @allianceplatform/ui which focused first on React components, with the idea being we could then roll out Django HTML template versions in a library to avoid the issues described above. In the meantime we introduced template tags like {% Button %} that just rendered the React version under the hood.
Why
Proposed Public Interface
Naming
{% ui.button %},{% ui.button_group %}, etc.{% Button %},{% ButtonGroup %}etc.{% ui 'button' %},{% button %}or switch out implementation on{% Button %}(breaking change)API Compatibility
ui.*tags should mirror React component props/defaults where practical.Runtime Behavior
data-djidor similar on container<script type="module">and callattach(element)Assets
Exstensible
Scope
Initial scope would be those that lend themselves to no/low JS: buttons, tables, tabs etc. menubar has slightly higher JS requirement but a bigger payoff given it's used on every page for navigation, so would be part of initial scope.
HTMX
No immediate plans to adopt this, but this change would also enable server-rendered components to work naturally in HTMX flows without React boundaries.
e.g.:
ui.tablecan support pagination/filter updates viahx-get/hx-swapwhile preserving Alliance UI styling(this is me assuming a few things based on my understanding without having used HTMX)
Examples