djust docs
Browse documentation
reference

Directive reference

All 68 dj-* directives, generated from the framework.

On this page

Every dj-* directive djust understands, generated from djust.schema.get_surface_manifest() in the pinned framework.

68 directives across 13 categories. This page is generated — if a directive is missing here it is missing from the framework, not from the docs.

Categories

Events

dj-blur

Send event when element loses focus

Value: handler_name

<input dj-blur="validate_field" name="email">

dj-change

Send event on input change (fires on blur for text, immediately for checkboxes/selects)

Value: handler_name

<select dj-change="filter_by"><option>All</option></select>

dj-click

Send event to server on click

Value: handler_name or handler_name('arg1', arg2)

<button dj-click="increment">+1</button>

dj-click-away

Fire a server event when a click occurs outside this element (commonly used to close dropdowns/popovers).

Value: handler_name

<div dj-click-away="close_menu">...</div>

dj-document-*

Bind a keydown/keyup/click/scroll/resize listener scoped to document instead of the element. Supports an optional '.key' modifier suffix for key events.

Value: handler_name

<div dj-document-click="track_page_click">...</div>

dj-focus

Send event when element receives focus

Value: handler_name

<input dj-focus="track_focus" name="search">

dj-input

Send event on every keystroke (auto-debounced 300ms for text, throttled for range/number)

Value: handler_name

<input dj-input="search" name="query">

dj-keydown

Send event on keydown. Supports key modifiers (e.g., dj-keydown.enter).

Value: handler_name or handler_name.enter

<input dj-keydown.enter="submit_search">

dj-keyup

Send event on keyup. Supports key modifiers like dj-keydown.

Value: handler_name or handler_name.escape

<input dj-keyup.escape="clear_search">

dj-mounted

Fire a server event the first time this element enters the DOM after initial page mount (e.g. an element revealed by a later {% if %} patch or a modal that opens later). Fires once per DOM node.

Value: handler_name

<div dj-mounted="chart_ready" data-value-chart-id="{{ id }}">...</div>

dj-mouseenter

Send event when the pointer enters the element. Non-bubbling: entering a child fires neither the parent's dj-mouseleave nor a second dj-mouseenter.

Value: handler_name

<div dj-mouseenter="preview">Hover me</div>

dj-mouseleave

Send event when the pointer leaves the element. Non-bubbling: moving into a child element does not fire it.

Value: handler_name

<div dj-mouseenter="preview" dj-mouseleave="hide_preview">Hover me</div>

dj-mutation

Fire a server event when this element's attributes or children change (bridges third-party widgets — charts, maps, rich-text editors — that mutate the DOM outside djust's control). Observes attribute changes if dj-mutation-attr is set, otherwise observes childList changes.

Value: handler_name

<div dj-mutation="on_change" dj-mutation-attr="class,style">...</div>

Related

  • dj-mutation-attr — Comma-separated attribute names to observe (default: observe childList instead).
  • dj-mutation-debounce — Coalesce bursts of mutations within N ms into one server event (default: 150).

dj-paste

Fire a server event on paste, with structured payload (text, html, and file metadata from the clipboard). Pasted files flow through the dj-upload pipeline rather than the WebSocket event frame.

Value: handler_name

<div dj-paste="handle_paste" contenteditable>...</div>

Related

  • dj-paste-suppress — Prevent the browser's default paste behavior after dispatch.

dj-poll

Declarative polling: periodically send event to server. Pauses when tab is hidden.

Value: handler_name

<div dj-poll="refresh_data" dj-poll-interval="5000">...</div>

dj-shortcut

Bind one or more keyboard shortcuts to server events. Comma-separated bindings of the form '[modifier+...]key:handler[:prevent]'. Ignored while a form input has focus unless dj-shortcut-in-input is also present.

Value: 'ctrl+k:open_search,escape:close_modal:prevent'

<body dj-shortcut="ctrl+k:open_search,escape:close_modal:prevent">

Related

  • dj-shortcut-in-input — Opt-in flag: also fire the shortcut while a form field has focus.

dj-submit

Send form data to server on submit. Calls e.preventDefault() and e.target.reset().

Value: handler_name

<form dj-submit="create_item"><input name="title"><button>Add</button></form>

dj-window-*

Bind a keydown/keyup/click/scroll/resize listener scoped to window instead of the element — for global shortcuts and viewport-level events. Supports an optional '.key' modifier suffix for key events.

Value: handler_name

<div dj-window-keydown.escape="close_modal">...</div>

Two-way binding

dj-force-value

Opt a focused form field into server-authoritative value sync during VDOM patches (by default, focused fields are skipped to preserve what the user is typing).

Value: (no value needed)

<input dj-model="draft" dj-force-value>

dj-model

Two-way data binding between form element and server state. Syncs on 'input' event by default.

Value: field_name

<input type="text" dj-model="search_query">

Loading states

dj-disable-with

Disable the element and swap its text while its triggering event is in flight; original text is restored on response.

Value: loading text

<button dj-click="save" dj-disable-with="Saving...">Save</button>

dj-form-pending

React to an ancestor form's dj-submit being in-flight, without writing a hook. React 19 useFormStatus equivalent.

Value: 'hide' | 'show' | 'disabled'

<form dj-submit="save"><span dj-form-pending="show">Saving...</span></form>

dj-loading

Shorthand form: disable this element while the named event is in flight (equivalent to dj-loading.disable, but scoped to a specific event name rather than the element's own triggering event).

Value: event_name

<button dj-loading="save">Save</button>

dj-loading.class

Add CSS class while event is in flight

Value: class_name

<button dj-click="save" dj-loading.class="opacity-50">Save</button>

dj-loading.disable

Disable element while event is in flight

Value: (no value needed)

<button dj-click="save" dj-loading.disable>Save</button>

dj-loading.for

Explicit form of the dj-loading shorthand: works on any element (not just the one triggering the event) — react while the named event is in flight anywhere on the page.

Value: event_name

<span dj-loading.for="save">Saving...</span>

dj-loading.hide

Hide element while event is in flight

Value: (no value needed)

<div dj-loading.hide>Normal content</div>

dj-loading.show

Show element (set display) while event is in flight

Value: display_value (default: 'block')

<div dj-loading.show="flex" style="display:none">Loading...</div>

dj-lock

Prevent duplicate submissions: locks the element (disables form fields, adds a CSS class otherwise) on first trigger and skips subsequent triggers until the response unlocks it.

Value: (no value needed)

<button dj-click="submit_order" dj-lock>Place Order</button>

DOM manipulation

dj-cloak

Hide this element (display:none via injected CSS) until the LiveView mount completes — prevents a flash of unstyled/un-hydrated content. Removed automatically once mounted.

Value: (no value needed)

<div dj-cloak>Loading skeleton...</div>

dj-dialog

Native <dialog> modal integration. Toggling the value between 'close'/'open' calls showModal()/close() on the element.

Value: 'open' | 'close'

<dialog id="settings" dj-dialog="{{ show_settings|yesno:'open,close' }}">...</dialog>

Related

  • dj-dialog-close-event — Server event fired when the user closes the dialog client-side (Escape, backdrop click), keeping server state in sync.

dj-ignore-attrs

Mark HTML attributes as client-owned so VDOM SetAttr patches skip them — for browser-native elements (<dialog open>, <details open>) and third-party JS that manages attributes the server doesn't know about.

Value: comma-separated attribute names

<dialog dj-ignore-attrs="open">...</dialog>

dj-scroll-into-view

Automatically scroll this element into view after a DOM update.

Value: (no value needed) | scrollIntoView options string

<div id="latest-message" dj-scroll-into-view></div>

dj-sticky-scroll

Keep a scrollable container pinned to the bottom as new content is appended, backing off (and re-arming) based on user scroll position.

Value: (no value needed)

<div dj-sticky-scroll style="overflow-y: auto; height: 400px">...</div>

dj-target

Scope the server re-render to a specific element (CSS selector)

Value: CSS selector (e.g., #sidebar, .panel)

<button dj-click="refresh_sidebar" dj-target="#sidebar">Refresh</button>

dj-update

Control how server HTML updates are applied to this element

Value: append | prepend | replace | ignore

<ul dj-update="append" id="messages">{% for msg in messages %}<li>{{ msg }}</li>{% endfor %}</ul>

Animation & transitions

dj-flip

FLIP-technique reorder animation: when a child of this element reorders, animate it from its old screen position to its new one.

Value: (no value needed)

<ul dj-flip>{% for item in items %}<li id="item-{{ item.id }}">{{ item.label }}</li>{% endfor %}</ul>

Related

  • dj-flip-duration — Transition duration in ms (default: 300).
  • dj-flip-easing — CSS easing function for the transform transition.

dj-remove

Declarative CSS exit transition. When a VDOM patch would remove this element, djust delays the removal until the transition completes (or a fallback timeout fires).

Value: 'start active end' | 'class-name'

<li dj-remove="fade-out">Toast</li>

Related

  • dj-remove-duration — Override the fallback timeout in ms (default: 600, clamped 0-30000).

dj-transition

Declarative CSS enter transition. Three-token form 'start active end' applies each class in a phase; single-token short form applies one class and waits for transitionend.

Value: 'start active end' | 'class-name'

<div dj-transition="opacity-0 transition-opacity-300 opacity-100">Fades in</div>

dj-transition-group

Orchestrate enter/leave animations for a list of children by wiring dj-transition/dj-remove specs onto each child automatically.

Value: (no value, use dj-group-enter/dj-group-leave) | 'enter-spec | leave-spec'

<ul dj-transition-group dj-group-enter="opacity-0 transition-opacity-300 opacity-100" dj-group-leave="opacity-100 transition-opacity-300 opacity-0">...</ul>

Related

  • dj-group-enter — Enter transition spec applied to newly-added children.
  • dj-group-leave — Leave transition spec applied to removed children.
  • dj-group-appear — Also animate children present on first render (not just later additions).

dj-view-transitions

Opt in to wrapping VDOM patches in the browser's document.startViewTransition() API (cross-fade by default; view-transition-name enables shared-element morphs). Placed on <body>. No-ops gracefully when unsupported (Firefox) or when the user has requested prefers-reduced-motion: reduce.

Value: (no value needed)

<body dj-view-transitions>

dj-navigate

Navigate to a different LiveView over the existing WebSocket (no page reload)

Value: URL path

<a dj-navigate="/items/42/">View Item</a>

dj-patch

Update URL params without remounting the view (client-side pushState + server url_change)

Value: URL path or query string

<a dj-patch="?page=2&sort=name">Page 2</a>

dj-patch-reload

Opt-in escape hatch: force a full page navigation for this dj-patch/dj-navigate link instead of an in-place client-side URL update.

Value: (no value needed)

<a dj-patch="?page=2" dj-patch-reload>Page 2</a>

Streaming

dj-stream

Mark element as a stream target for server-pushed DOM operations

Value: stream_name

<ul dj-stream="messages">{% for msg in streams.messages %}<li>{{ msg }}</li>{% endfor %}</ul>

dj-stream-mode

Default insertion mode for streaming text content

Value: append | replace | prepend

<div dj-stream="output" dj-stream-mode="append"></div>

dj-viewport-bottom

Fire a server event once when the last child of this container enters the viewport (bidirectional infinite scroll, forward pagination).

Value: handler_name

<div dj-stream="messages" dj-viewport-bottom="load_newer">...</div>

Related

  • dj-viewport-threshold — IntersectionObserver threshold, 0-1 (default: 0.1).

dj-viewport-top

Fire a server event once when the first child of this container enters the viewport (bidirectional infinite scroll, backward pagination).

Value: handler_name

<div dj-stream="messages" dj-viewport-top="load_older">...</div>

Related

  • dj-viewport-threshold — IntersectionObserver threshold, 0-1 (default: 0.1).

Uploads

dj-upload

Bind a file input to an upload slot (binary WebSocket upload)

Value: upload_slot_name

<input type="file" dj-upload="avatar">

dj-upload-drop

Mark element as a drag-and-drop zone for file uploads

Value: upload_slot_name

<div dj-upload-drop="attachments">Drop files here</div>

dj-upload-preview

Container for image upload previews (auto-populated with thumbnails)

Value: upload_slot_name

<div dj-upload-preview="avatar"></div>

dj-upload-progress

INERT — registered as an attribute but no client code reads it; no progress bar is created. Render progress server-side instead.

Value: upload_slot_name

<div dj-upload-progress="attachments"></div>

Performance

dj-key

Stable identity for an item in a list, so the VDOM differ can MOVE a row instead of destroying and rebuilding it when the list reorders. Without it the differ falls back to positional diffing, which discards the DOM node — losing focus, input values, scroll position and any client-side state attached to it. Read by the Rust template parser into VNode.key (crates/djust_vdom/src/parser.rs), where data-key is accepted as an equivalent spelling. Keys must be UNIQUE among siblings: a duplicate is ambiguous, so the differ demotes those siblings to positional diffing and warns DJE-051. Prefer this over an authored dj-id, which the parser ignores (#1253).

Value: unique_value_per_item

{% for item in items %}<li dj-key="{{ item.id }}">{{ item.name }}</li>{% endfor %}

Related

  • data-key — Equivalent spelling, accepted by the same parser branch. Also the default height-cache key for dj-virtual in variable-height mode (see dj-virtual-key-attr).

dj-lazy

Defer WebSocket connection and LiveView mounting until the element enters the viewport, is clicked, or is hovered — reduces memory/connections for below-fold LiveViews.

Value: 'viewport' (default) | 'click' | 'hover'

<div dj-view="my_view" dj-lazy>...</div>

dj-prefetch

Prefetch a same-origin link's page via the service worker when the user hovers over it. Value 'false' opts a link out.

Value: (no value needed) | 'false'

<a href="/reports/" dj-prefetch>View reports</a>

dj-track-static

Detect stale static assets (script/link) after a WebSocket reconnect and dispatch a dj:stale-assets event, or reload the page automatically when the value is 'reload'.

Value: (no value needed) | 'reload'

<script dj-track-static src="{% static 'js/app.abc123.js' %}"></script>

dj-virtual

Render only the visible slice of a large list (windowed/virtual list with DOM recycling). Value names the context list variable driving the list.

Value: items_var_name

<div dj-virtual="items" dj-virtual-item-height="48">...</div>

Related

  • dj-virtual-item-height — Fixed pixel height per item.
  • dj-virtual-variable-height — Opt into variable heights, measured via ResizeObserver.
  • dj-virtual-overscan — Rows rendered above/below the viewport (default: 3).
  • dj-virtual-estimated-height — Baseline height for unmeasured items in variable mode (default: 50).
  • dj-virtual-key-attr — Attribute used as the height-cache key in variable mode (default: 'data-key').

Recovery

dj-auto-recover

After a WebSocket reconnect, serialize this container's form field values and data-* attributes and fire the named event so the server can restore client-only state that didn't round-trip through the view.

Value: handler_name

<div dj-auto-recover="restore_draft">...</div>

Related

  • dj-no-recover — Exclude an individual field within (or outside) an auto-recover container from recovery serialization.

Modifiers

dj-confirm

Show browser confirm() dialog before sending event. Cancels if user declines.

Value: confirmation message

<button dj-click="delete_item" dj-confirm="Are you sure?">Delete</button>

dj-debounce

Debounce a rate-limited event directive (dj-input/dj-change/dj-keydown/dj-keyup) by N milliseconds, or 'blur' to defer until the field loses focus. Takes precedence over the legacy data-debounce attribute.

Value: milliseconds | 'blur'

<input dj-input="search" dj-debounce="500">

dj-no-submit

Swallow Enter-key submits from text inputs in this form (the 'enter' mode); prevents accidental submission on multi-field forms.

Value: 'enter'

<form dj-submit="save" dj-no-submit="enter">...</form>

dj-params

DEPRECATED (0.3.2 -> 0.3.6+ migration): JSON blob of extra params to send with an event. Use dj-value-* attributes instead — data-/dj-value- keys take precedence over dj-params keys with the same name.

Value: '{"key": "value"}' JSON blob

<button dj-click="save" dj-params='{"source": "toolbar"}'>Save</button>

dj-poll-interval

Polling interval in milliseconds for dj-poll (default: 5000)

Value: milliseconds

<div dj-poll="refresh" dj-poll-interval="3000">...</div>

dj-throttle

Throttle a rate-limited event directive to at most once per N milliseconds. Takes precedence over the legacy data-throttle attribute.

Value: milliseconds

<input dj-input="live_search" dj-throttle="200">

dj-trigger-action

Native POST bridge: when the server pushes a trigger-action event, submit this form natively (full page navigation) instead of over the WebSocket — for flows that need a real HTTP redirect (e.g. payment providers).

Value: (no value needed)

<form action="/checkout/" method="post" dj-trigger-action>...</form>

dj-value-*

Pass static context alongside any event directive as typed params (Phoenix LiveView's phx-value-* equivalent). Supports the same ':type' coercion suffixes as data-* attributes.

Value: any string (kebab-case suffix -> snake_case param key)

<button dj-click="delete" dj-value-item-id:int="{{ item.id }}">Delete</button>

Hooks

dj-hook

Attach a client-side JS hook to this element. Hook receives mounted/updated/destroyed callbacks.

Value: HookName (registered in window.djust.hooks)

<canvas dj-hook="MyChart" data-values="{{ chart_data }}"></canvas>

Related

  • dj-hook-value-* — Typed value exposed to the hook as this.values.<camelCase> (ADR-025). e.g. dj-hook-value-code='"007"' -> this.values.code. Kebab-case attribute suffix maps to camelCase property; read-only from JS.
  • dj-hook-target — Marks a descendant of the hook's element as a named scoped query target, retrieved via this.target(name) / this.targets(name).

Client

dj-copy

Copy attribute value to clipboard on click (client-only, no server event)

Value: text to copy (can use template variables)

<button dj-copy="{{ api_key }}">Copy Key</button>

Related

  • dj-copy-class — CSS class applied to the button while showing feedback (default: 'dj-copied')
  • dj-copy-event — Server event name to also fire after a successful copy
  • dj-copy-feedback — Temporary button text shown after copying (default: 'Copied!')