Repository navigation
Template contract
Applies from 1.0.0. This is the explicit presentation surface covered by Stability. Use it with Templates. Translated values may be strings or Django lazy strings; exact wording is not API.
commentail/block.html always receives:
| Fields | Meaning |
|---|---|
language_code |
Active language string or None |
discussion_id, page_id
|
Integer IDs; page_id is None for ordinary objects |
hidden |
Boolean; hidden widgets render no section |
entered_text, entered_name, entered_email, error
|
Strings; text is empty during editing; error may be translated |
editing |
Editor mapping below, or None |
options |
Readable editorial settings below |
options exposes mode (open/read_only/hidden), moderation
(all/guests/none/rules), access (all/registered/guests/none), max_length
(integer), clickable_links, notify_publication and notify_rejection (booleans).
highlight_staff (boolean, from 1.1.0) controls Site-wide staff decorations.
These fields are public; the internal Python class is not.
Only when hidden=False, the following fields are available:
| Fields | Meaning |
|---|---|
rows, own
|
Public root cards and current visitor's private cards |
count |
Published message count, including replies |
window_token |
Opaque root pagination window |
more_url, cancel_reply_url, submit_url
|
Server-generated strings; more_url may be empty |
can_post, guest_email_confirmed, structured_microdata
|
Booleans |
form_key, main_form_key
|
Opaque strings; the latter is populated for an active reply |
captcha |
CaptchaTask or None |
remembered_email |
Confirmed guest email string or empty string |
reply_to |
Published addressee card or None |
structured_comments |
List passed directly to commentail_json_ld; empty when disabled |
mail_notice is present only for a one-time translated notice. Use conditional
checks for optional fields. Django supplies request through its request context
processor and csrf_token through its normal CSRF integration. Additional host
context-processor fields do not become Commentail API.
Widget context and private cards are visitor-specific; never place them in a shared cache.
Public/private cards expose id (integer), display_name, initials, gradient
(strings), avatar_url (string or None), body (already escaped SafeString with
permitted links/line breaks), published_at and edited_at (aware datetime or None),
status, status_label, reason, resend_url, edit_url, permalink, reply_url,
reply_to_id (integer or None), reply_to_name (string) and schema (metadata or None).
From 1.1.0, highlight_staff and show_crown are additional boolean card fields.
They already account for the Site switch and the current active author's flags.
Built-in templates share commentail/author.html for the name badge and
commentail/avatar.html for the avatar and crown, including private pending cards.
The crown sits outside the decorative, clipped avatar with an accessible label;
author text and schema metadata are unchanged. Custom author markup must render these
fields to adopt highlighting; existing overrides remain valid.
Statuses are awaiting_email/pending/published/rejected/hidden/deleted;
status_label is translated and must not be parsed. reason is populated only for
rejection. Optional action URLs may be empty. A reply URL alone does not authorize replying.
Root cards additionally expose reply_count, opened, reply_window,
expand_url and more_replies. replies exists only when opened=True; children
have base-card fields without recursive root additions. Private awaiting-email
cards additionally expose delivery_message and confirmation_expires_at.
A pending revision stays private; public output retains approved text.
schema exposes identifier, url, target, author, text, published
(strings), and modified/parent (string or None). Dates are ISO 8601. Private
cards and hidden/deleted placeholders have no schema. Do not apply safe to raw
user text or assemble internal schema classes yourself.
Preserve POST actions and CSRF, hidden key (form_key), optional reply_to,
textarea text, guest name/email, and CAPTCHA challenge/answer.
The refresh button submits refresh=1 with formnovalidate. Keep the same key for
an explicit retry after network failure; do not automatically retry a POST.
The guest name field retains its documented 40-grapheme limit.
editing has id, text, error, can_edit, url and cancel_url. Only render
a submit form when can_edit=True. Preserve hidden edit_comment, textarea text,
CSRF and the server action. Label/required/aria-describedby and error alerts
remain part of the accessible forms. No public subscription checkbox is promised.
commentail/base.html exposes blocks title, extra_head, heading, content
and return_label. Keep the language, viewport, accessible heading and
strict-origin referrer policy. A global no-referrer policy can break native CSRF.
Base/action contexts always have language_code, page_title, return_url.
Ordinary action pages add purpose, token, message, error, text,
status_label, reason; only view exposes text/reason. Errors instead set
unavailable=True, error, return_url="/" and omit the action/token/content
fields. Confirm/unsubscribe forms remain native POST forms outside the widget;
edit redirects to the inline editor. See mail paths and context.
| Hook | Requirement |
|---|---|
.commentail[data-discussion], id="commentail", lang, data-window
|
One replaceable root for the discussion, active language and opaque pagination window |
data-published-label, data-network-error
|
Localized status/error labels |
.commentail-network-error |
Initially hidden descendant with role=alert |
.commentail-error[role="alert"], .commentail-header h2
|
Error and fallback focus targets |
.commentail-comment, id="commentail-<id>", .commentail-content
|
Card, permanent anchor and target for inserted reply/editor content |
.commentail-pending, id="commentail-private-<id>", optional data-reply-to |
Private result card and addressee |
.commentail-status, first strong in card |
Result status and author name for announcements |
.commentail-mail-notice |
One-time notice with role=status |
.commentail-replies[data-thread], data-open, data-window |
Root ID and opened-thread window |
template.commentail-main-template |
First content element is a complete independent main form |
.commentail-editor |
Inline editor/error/cancel wrapper inside the card |
.commentail-avatar-image, textarea.commentail-input
|
Broken-avatar fallback and textarea sizing |
input[data-commentail-name-limit] |
Guest-name limit used by progressive enhancement |
a[data-commentail-navigation] |
Working same-origin href, usable without JS |
| data-commentail-focus="text" | Navigation's requested field focus |
| data-commentail-reply, data-commentail-edit | Addressee/comment ID, plus navigation hook and server href |
| data-commentail-cancel, data-commentail-edit-cancel | Reply/edit cancel controls with navigation hook and server href |
.commentail-form[data-reply-to], .commentail-edit-form[data-edit-comment]
|
Active reply/editor and corresponding ID |
details.commentail-menu > summary |
Author menu; Escape closes and returns focus |
The script owns aria-busy, temporary tabindex/disabled state, the temporary reply
form class and the persistent .commentail-announcement live region before the
replaceable root. Overrides must not hard-code those transient states or move
the announcement inside the replaced fragment. Native links/forms must work when
JavaScript or enhancement APIs are absent. Main/reply/edit drafts remain separate.
Multiple copies of the same discussion widget on one page are not promised.
- Home
- Installation
- Configuration
- Moderation
- Rules and CSV
- Guest comments
- Replies and editing
- Email and worker
- Styling
- Templates
- Recent comments
- Structured data
- Callbacks
- Object adapters
- Security and privacy
- Deployment
- Performance
- Troubleshooting
- Example and testing
- Release 0.1.0
- Release 0.1.1
- Release 0.2.0
- Stability
- Template contract
- Release 1.0.0
- Release 1.1.0
- Release 1.2.0
- Changelog
- Roadmap
- Support