From 85665af504973378735ca840ab50c69ee4102fc1 Mon Sep 17 00:00:00 2001
From: LB <mail@lb.ee>
Date: Sat, 8 Mar 2025 16:31:26 +1000
Subject: [PATCH] Update Stimulus controller `@example` JSDoc items

- Use consistent ```html markdown blocks
- Use consistent two space indentation
- Move the description to the example row, not on the new line where applicable
- Add missing examples were practical
---
 client/src/controllers/ActionController.ts    | 43 +++++++-----
 client/src/controllers/AutosizeController.ts  |  2 +
 client/src/controllers/BlockController.ts     | 20 +++---
 client/src/controllers/BulkController.ts      |  6 +-
 client/src/controllers/ClipboardController.ts |  4 +-
 client/src/controllers/CloneController.ts     | 12 ++--
 client/src/controllers/CountController.ts     |  6 +-
 client/src/controllers/DialogController.ts    |  8 ++-
 .../src/controllers/DismissibleController.ts  |  4 +-
 client/src/controllers/DropdownController.ts  |  6 +-
 client/src/controllers/FormsetController.ts   | 48 +++++++-------
 client/src/controllers/InitController.ts      |  6 ++
 client/src/controllers/LocaleController.ts    |  9 +++
 client/src/controllers/OrderableController.ts |  9 +++
 client/src/controllers/ProgressController.ts  |  6 +-
 client/src/controllers/RevealController.ts    |  6 +-
 client/src/controllers/SlugController.ts      |  2 +
 client/src/controllers/SubmitController.ts    |  5 +-
 client/src/controllers/SwapController.ts      | 65 ++++++++++---------
 client/src/controllers/SyncController.ts      |  2 +
 client/src/controllers/TagController.ts       |  6 +-
 client/src/controllers/TeleportController.ts  |  8 ++-
 client/src/controllers/TooltipController.ts   |  4 +-
 client/src/controllers/UnsavedController.ts   |  8 +++
 client/src/controllers/UpgradeController.ts   | 14 +++-
 client/src/controllers/ZoneController.ts      |  2 +-
 26 files changed, 204 insertions(+), 107 deletions(-)

diff --git a/client/src/controllers/ActionController.ts b/client/src/controllers/ActionController.ts
index 6e5cf002f4..c579a73228 100644
--- a/client/src/controllers/ActionController.ts
+++ b/client/src/controllers/ActionController.ts
@@ -7,50 +7,61 @@ import { WAGTAIL_CONFIG } from '../config/wagtailConfig';
  * triggering a form submission where the form is created dynamically
  * in the DOM and then submitted.
  *
- * @example - triggering a click
+ * @example - Triggering a click
+ * ```html
  * <button
- *  type="button"
- *  data-controller="w-action"
- *  data-action="some-event#click"
+ *   type="button"
+ *   data-controller="w-action"
+ *   data-action="some-event#click"
  * >
- *  Go
+ *   Go
  * </button>
+ * ```
  *
- * @example - triggering a dynamic POST submission
+ * @example - Triggering a dynamic POST submission
+ * ```html
  * <button
- *  type="submit"
- *  data-controller="w-action"
- *  data-action="w-action#post"
- *  data-w-action-url-value='url/to/post/to'
+ *   type="submit"
+ *   data-controller="w-action"
+ *   data-action="w-action#post"
+ *   data-w-action-url-value='url/to/post/to'
  * >
  *  Enable
  * </button>
+ * ```
  *
- * @example - triggering a POST request via sendBeacon
+ * @example - Triggering a POST request via sendBeacon
+ * ```html
  * <button data-controller="w-action" data-action="blur->w-action#sendBeacon">
- *  If you move focus away from this button, a POST request will be sent.
+ *   If you move focus away from this button, a POST request will be sent.
  * </button>
+ * ```
  *
- * @example - triggering a dynamic redirect
- * // note: a link is preferred normally
+ * @example - Triggering a dynamic redirect (a link is normally preferred)
+ * ```html
  * <form>
  *   <select name="url" data-controller="w-action" data-action="change->w-action#redirect">
  *     <option value="/path/to/1">1</option>
  *     <option value="/path/to/2">2</option>
  *   </select>
  * </form>
+ * ```
  *
- * @example - triggering selection of the text in a field
+ * @example - Triggering selection of the text in a field
+ * ```html
  * <form>
  *   <textarea name="url" data-controller="w-action" data-action="click->w-action#select">
  *     This text will all be selected on focus.
  *   </textarea>
  * </form>
+ * ```
  *
- * @example - ensuring a button's click does not propagate
+ * @example - Ensuring a button's click does not propagate
+ * ```html
  * <div>
  *   <button type="button" data-controller="w-action" data-action="w-action#noop:stop">Go</button>
  * </div>
+ * ```
  */
 export class ActionController extends Controller<
   HTMLButtonElement | HTMLInputElement | HTMLTextAreaElement
diff --git a/client/src/controllers/AutosizeController.ts b/client/src/controllers/AutosizeController.ts
index d632893612..c9e404763f 100644
--- a/client/src/controllers/AutosizeController.ts
+++ b/client/src/controllers/AutosizeController.ts
@@ -7,7 +7,9 @@ import { debounce } from '../utils/debounce';
  * types in the field so that it expands to show all content.
  *
  * @example
+ * ```html
  * <textarea data-controller="w-autosize"></textarea>
+ * ```
  */
 export class AutosizeController extends Controller<HTMLTextAreaElement> {
   resizeObserver?: ResizeObserver;
diff --git a/client/src/controllers/BlockController.ts b/client/src/controllers/BlockController.ts
index a240acf382..7c9d3cd864 100644
--- a/client/src/controllers/BlockController.ts
+++ b/client/src/controllers/BlockController.ts
@@ -12,21 +12,25 @@ declare global {
  * Used to initialize the top-level element of a BlockWidget (the form widget for a StreamField).
  *
  * @example
+ * ```html
  * <div
- *  id="some-id"
- *  data-controller="w-block"
- *  data-w-block-data-value='{"_args":["..."], "_type": "wagtail.blocks.StreamBlock"}'
+ *   id="some-id"
+ *   data-controller="w-block"
+ *   data-w-block-data-value='{"_args":["..."], "_type": "wagtail.blocks.StreamBlock"}'
  * >
  * </div>
+ * ```
  *
- * @example - with initial arguments
+ * @example - With initial arguments
+ * ```html
  * <div
- *  id="some-id"
- *  data-controller="w-block"
- *  data-w-block-data-value='{"_args":["..."], "_type": "wagtail.blocks.StreamBlock"}'
- *  data-w-block-arguments-value='[[{ type: "paragraph_block", value: "..."}], {messages:["An error..."]}]'
+ *   id="some-id"
+ *   data-controller="w-block"
+ *   data-w-block-data-value='{"_args":["..."], "_type": "wagtail.blocks.StreamBlock"}'
+ *   data-w-block-arguments-value='[[{ type: "paragraph_block", value: "..."}], {messages:["An error..."]}]'
  * >
  * </div>
+ * ```
  */
 export class BlockController extends Controller<HTMLElement> {
   static values = {
diff --git a/client/src/controllers/BulkController.ts b/client/src/controllers/BulkController.ts
index 1574651248..5c3973a460 100644
--- a/client/src/controllers/BulkController.ts
+++ b/client/src/controllers/BulkController.ts
@@ -14,6 +14,7 @@ type ToggleAllOptions = ToggleOptions & {
  * Adds the ability to collectively toggle a set of (non-disabled) checkboxes.
  *
  * @example - Basic usage
+ * ```html
  * <div data-controller="w-bulk">
  *   <input type="checkbox" data-action="w-bulk#toggleAll" data-w-bulk-target="all">
  *   <div>
@@ -26,6 +27,7 @@ type ToggleAllOptions = ToggleOptions & {
  * </div>
  *
  * @example - Showing and hiding an actions container
+ * ```html
  * <div data-controller="w-bulk" data-w-bulk-action-inactive-class="w-invisible">
  *   <div class="w-invisible" data-w-bulk-target="action" id="inner-actions">
  *     <button type="button">Some action</button>
@@ -37,8 +39,10 @@ type ToggleAllOptions = ToggleOptions & {
  *     <input data-action="w-bulk#toggle" data-w-bulk-target="item" type="checkbox" />
  *   </div>
  * </div>
+ * ```
  *
  * @example - Using groups to allow toggles to be controlled separately or together
+ * ```html
  * <table data-controller="w-bulk">
  *   <thead>
  *     <tr>
@@ -74,7 +78,7 @@ type ToggleAllOptions = ToggleOptions & {
  *     </td>
  *    </tfoot>
  * </table>
- *
+ * ```
  */
 export class BulkController extends Controller<HTMLElement> {
   static classes = ['actionInactive'];
diff --git a/client/src/controllers/ClipboardController.ts b/client/src/controllers/ClipboardController.ts
index 42aac3c8c8..b3e41b43bf 100644
--- a/client/src/controllers/ClipboardController.ts
+++ b/client/src/controllers/ClipboardController.ts
@@ -11,8 +11,8 @@ type CopyOptions = {
  * @example
  * ```html
  * <div data-controller="w-clipboard">
- *  <input type="text" value="Hello World" data-w-clipboard-target="value" />
- *  <button type="button" data-action="w-clipboard#copy">Copy</button>
+ *   <input type="text" value="Hello World" data-w-clipboard-target="value" />
+ *   <button type="button" data-action="w-clipboard#copy">Copy</button>
  * </div>
  * ```
  */
diff --git a/client/src/controllers/CloneController.ts b/client/src/controllers/CloneController.ts
index b3af9d537e..649bf47114 100644
--- a/client/src/controllers/CloneController.ts
+++ b/client/src/controllers/CloneController.ts
@@ -19,6 +19,7 @@ type AddOptions = {
  * Additionally, it will allow for clearing all previously added elements.
  *
  * @example - Using with the w-messages identifier
+ * ```html
  * <div
  *   data-controller="w-messages"
  *   data-action="w-messages:add@document->w-messages#add"
@@ -28,8 +29,9 @@ type AddOptions = {
  *   <ul data-w-messages-target="container"></ul>
  *   <template data-w-messages-target="template">
  *     <li data-message-status="error-or-success"><span></span></li>
- *  </template>
+ *   </template>
  * </div>
+ * ```
  *
  * @example - Using to show a temporary element with auto-clearing
  * ```html
@@ -39,12 +41,12 @@ type AddOptions = {
  *  data-w-clone-auto-clear-value="5_000"
  * >
  *   <div data-w-clone-target="container"></div>
- *   <template data-w-clone-target="template">
- *     <p>Page has loaded, this will be removed in 5 seconds.</p>
- *   </template>
+ *     <template data-w-clone-target="template">
+ *       <p>Page has loaded, this will be removed in 5 seconds.</p>
+ *     </template>
  *   </div>
  * </div>
- *
+ * ```
  */
 export class CloneController extends Controller<HTMLElement> {
   static classes = ['added', 'hide', 'show'];
diff --git a/client/src/controllers/CountController.ts b/client/src/controllers/CountController.ts
index 0a9c404569..e49ae90efa 100644
--- a/client/src/controllers/CountController.ts
+++ b/client/src/controllers/CountController.ts
@@ -9,10 +9,12 @@ const DEFAULT_ERROR_SELECTOR = '.error-message,.help-critical';
  * to `body.`
  *
  * @example
+ * ```html
  * <div data-controller="w-count">
- *  <span data-w-count-target="label"></span>
- *  <span class="error-message">An error</span>
+ *   <span data-w-count-target="label"></span>
+ *   <span class="error-message">An error</span>
  * </div>
+ * ```
  */
 export class CountController extends Controller<HTMLFormElement> {
   static classes = ['active'];
diff --git a/client/src/controllers/DialogController.ts b/client/src/controllers/DialogController.ts
index e73c6085f7..98c4e7a1ed 100644
--- a/client/src/controllers/DialogController.ts
+++ b/client/src/controllers/DialogController.ts
@@ -9,12 +9,14 @@ const FLOATING = 'floating';
  * scroll when the dialog is open.
  *
  * @example
+ * ```html
  * <div
- *    data-controller="w-dialog"
- *    data-w-dialog-theme-value="floating"
+ *   data-controller="w-dialog"
+ *   data-w-dialog-theme-value="floating"
  *   >
  *    <div data-w-dialog-target="body"></div>
- *  </div>
+ * </div>
+ * ```
  */
 export class DialogController extends Controller<HTMLElement> {
   static values = {
diff --git a/client/src/controllers/DismissibleController.ts b/client/src/controllers/DismissibleController.ts
index dad6e78005..bb8af8409f 100644
--- a/client/src/controllers/DismissibleController.ts
+++ b/client/src/controllers/DismissibleController.ts
@@ -34,13 +34,15 @@ export const updateDismissibles = (
  * that are rendered by the client (e.g. React) needs to be handled separately.
  *
  * @example
+ * ```html
  * <section
  *  data-controller="w-dismissible"
  *  data-w-dismissible-dismissed-class="w-dismissible--dismissed"
  *  data-w-dismissible-id-value="Whats new in Wagtail"
  * >
- *  <button type="button" data-action="w-dismiss#dismissible">Close</button>
+ *   <button type="button" data-action="w-dismiss#dismissible">Close</button>
  * </section>
+ * ```
  */
 export class DismissibleController extends Controller<HTMLElement> {
   static classes = ['dismissed'];
diff --git a/client/src/controllers/DropdownController.ts b/client/src/controllers/DropdownController.ts
index cde873b870..39b4680b3c 100644
--- a/client/src/controllers/DropdownController.ts
+++ b/client/src/controllers/DropdownController.ts
@@ -86,10 +86,12 @@ type TippyTheme = 'dropdown' | 'drilldown' | 'dropdown-button';
  * A Tippy.js tooltip with interactive "dropdown" options.
  *
  * @example
+ * ```html
  * <div data-controller="w-dropdown" data-w-dropdown-hide-on-click-value-"true">
- *  <button type="button" data-w-dropdown-target="toggle" aria-label="Actions"></button>
- *  <div data-w-dropdown-target="content">[…]</div>
+ *   <button type="button" data-w-dropdown-target="toggle" aria-label="Actions"></button>
+ *   <div data-w-dropdown-target="content">[…]</div>
  * </div>
+ * ```
  */
 export class DropdownController extends Controller<HTMLElement> {
   static targets = ['toggle', 'content'];
diff --git a/client/src/controllers/FormsetController.ts b/client/src/controllers/FormsetController.ts
index 8a85b251fa..14f4a33c24 100644
--- a/client/src/controllers/FormsetController.ts
+++ b/client/src/controllers/FormsetController.ts
@@ -10,30 +10,30 @@ import { runInlineScripts } from '../utils/runInlineScripts';
  * @example
  * ```html
  * <form data-controller="w-formset">
- *  <input type="hidden" name="form-TOTAL_FORMS" value="2" data-w-formset-target="totalFormsInput">
- *  <input type="hidden" name="form-MIN_NUM_FORMS" value="0" data-w-formset-target="minFormsInput">
- *  <input type="hidden" name="form-MAX_NUM_FORMS" value="50" data-w-formset-target="maxFormsInput">
- *  <input type="hidden" name="form-INITIAL_FORMS" value="2">
- *  <ul data-w-formset-target="forms">
- *    <li data-w-formset-target="child">
- *      <input type="text" name="form-0-name">
- *      <input type="hidden" name="form-0-DELETE" data-w-formset-target="deleteInput">
- *      <button type="button" data-action="w-formset#delete">Delete</button>
- *    </li>
- *    <li data-w-formset-target="child">
- *      <input type="text" name="form-1-name">
- *      <input type="hidden" name="form-1-DELETE" data-w-formset-target="deleteInput">
- *      <button type="button" data-action="w-formset#delete">Delete</button>
- *    </li>
- *  </ul>
- *  <button type="button" data-action="w-formset#add">Add</button>
- *  <template data-w-formset-target="template">
- *    <li data-w-formset-target="child">
- *      <input type="text" name="form-__prefix__-name">
- *      <input type="hidden" name="form-__prefix__-DELETE" data-w-formset-target="deleteInput">
- *      <button type="button" data-action="w-formset#delete">Delete</button>
- *    </li>
- *  </template>
+ *   <input type="hidden" name="form-TOTAL_FORMS" value="2" data-w-formset-target="totalFormsInput">
+ *   <input type="hidden" name="form-MIN_NUM_FORMS" value="0" data-w-formset-target="minFormsInput">
+ *   <input type="hidden" name="form-MAX_NUM_FORMS" value="50" data-w-formset-target="maxFormsInput">
+ *   <input type="hidden" name="form-INITIAL_FORMS" value="2">
+ *   <ul data-w-formset-target="forms">
+ *     <li data-w-formset-target="child">
+ *       <input type="text" name="form-0-name">
+ *       <input type="hidden" name="form-0-DELETE" data-w-formset-target="deleteInput">
+ *       <button type="button" data-action="w-formset#delete">Delete</button>
+ *     </li>
+ *     <li data-w-formset-target="child">
+ *       <input type="text" name="form-1-name">
+ *       <input type="hidden" name="form-1-DELETE" data-w-formset-target="deleteInput">
+ *       <button type="button" data-action="w-formset#delete">Delete</button>
+ *     </li>
+ *   </ul>
+ *   <button type="button" data-action="w-formset#add">Add</button>
+ *   <template data-w-formset-target="template">
+ *     <li data-w-formset-target="child">
+ *       <input type="text" name="form-__prefix__-name">
+ *       <input type="hidden" name="form-__prefix__-DELETE" data-w-formset-target="deleteInput">
+ *       <button type="button" data-action="w-formset#delete">Delete</button>
+ *     </li>
+ *   </template>
  * </form>
  * ```
  */
diff --git a/client/src/controllers/InitController.ts b/client/src/controllers/InitController.ts
index 0eee5d295f..7fb958676b 100644
--- a/client/src/controllers/InitController.ts
+++ b/client/src/controllers/InitController.ts
@@ -6,19 +6,25 @@ import { debounce } from '../utils/debounce';
  * add or remove classes when ready to be interacted with.
  *
  * @example - Dynamic classes when ready
+ * ```html
  * <div class="keep-me hide-me" data-controller="w-init" data-w-init-remove-class="hide-me" data-w-init-ready-class="loaded">
  *   When the DOM is ready, this div will have the class 'loaded' added and 'hide-me' removed.
  * </div>
+ * ```
  *
  * @example - Custom event dispatching
+ * ```html
  * <div class="keep-me hide-me" data-controller="w-init" data-w-init-event-value="custom:event other-custom:event">
  *   When the DOM is ready, two additional custom events will be dispatched; `custom:event` and `other-custom:event`.
  * </div>
+ * ```
  *
  * @example - Detail dispatching
+ * ```html
  * <article data-controller="w-init" data-w-init-detail-value='{"status": "success", "message": "Article has entered the room"}'>
  *  When the DOM is ready, the detail with value of a JSON object above will be dispatched.
  * </article>
+ * ```
  */
 export class InitController extends Controller<HTMLElement> {
   static classes = ['ready', 'remove'];
diff --git a/client/src/controllers/LocaleController.ts b/client/src/controllers/LocaleController.ts
index 887e2b77c7..369c932347 100644
--- a/client/src/controllers/LocaleController.ts
+++ b/client/src/controllers/LocaleController.ts
@@ -2,6 +2,15 @@ import { Controller } from '@hotwired/stimulus';
 
 /**
  * Localizes elements in the current locale.
+ *
+ * @example
+ * ```html
+ * <select data-controller="w-locale" data-action="w-locale#localizeTimeZoneOptions">
+ *   <option value="" selected>Use server time zone</option>
+ *   <option value="Asia/Jakarta">Asia/Jakarta</option>
+ *   <option value="Asia/Tokyo">Asia/Tokyo</option>
+ * </select>
+ * ```
  */
 export class LocaleController extends Controller<HTMLSelectElement> {
   /**
diff --git a/client/src/controllers/OrderableController.ts b/client/src/controllers/OrderableController.ts
index 94ede99322..4ffa05510f 100644
--- a/client/src/controllers/OrderableController.ts
+++ b/client/src/controllers/OrderableController.ts
@@ -12,6 +12,15 @@ enum Direction {
  *
  * Once re-ordering is completed an async request will be made to the
  * provided URL to submit the update per item.
+ *
+ * @example
+ * ```html
+ * <fieldset data-controller="w-orderable" data-w-orderable-url-value="/path/to/orderable/">
+ *   <input type="button" data-w-orderable-target="item" data-w-orderable-item-id="1" value="Item 1"/>
+ *   <input type="button" data-w-orderable-target="item" data-w-orderable-item-id="2" value="Item 2"/>
+ *   <input type="button" data-w-orderable-target="item" data-w-orderable-item-id="3" value="Item 3"/>
+ * </fieldset>
+ * ```
  */
 export class OrderableController extends Controller<HTMLElement> {
   static classes = ['active', 'chosen', 'drag', 'ghost'];
diff --git a/client/src/controllers/ProgressController.ts b/client/src/controllers/ProgressController.ts
index 6165432e83..22317d616f 100644
--- a/client/src/controllers/ProgressController.ts
+++ b/client/src/controllers/ProgressController.ts
@@ -7,6 +7,7 @@ const DEFAULT_CLASS = 'button-longrunning';
  * until the duration has elapsed. Will also update the button's label while in progress.
  *
  * @example
+ * ```html
  * <button
  *   type="submit"
  *   class="button button-longrunning"
@@ -16,9 +17,10 @@ const DEFAULT_CLASS = 'button-longrunning';
  *   data-w-progress-duration-seconds-value="40"
  *   data-action="w-progress#activate"
  * >
- *  {% icon name="spinner" %}
- *  <em data-w-progress-target="label">{% trans 'Sign in' %}</em>
+ *   {% icon name="spinner" %}
+ *   <em data-w-progress-target="label">{% trans 'Sign in' %}</em>
  * </button>
+ * ```
  */
 export class ProgressController extends Controller<HTMLButtonElement> {
   static classes = ['active'];
diff --git a/client/src/controllers/RevealController.ts b/client/src/controllers/RevealController.ts
index 8d74c50d24..16406d8023 100644
--- a/client/src/controllers/RevealController.ts
+++ b/client/src/controllers/RevealController.ts
@@ -8,10 +8,12 @@ import { Controller } from '@hotwired/stimulus';
  * @see https://w3c.github.io/aria/#aria-expanded
  *
  * @example
+ * ```html
  * <section data-controller="w-reveal">
- *  <button type="button" data-action="w-reveal#toggle" data-w-reveal-target="toggle" aria-controls="my-content" type="button">Toggle</button>
- *  <div id="my-content">CONTENT</div>
+ *   <button type="button" data-action="w-reveal#toggle" data-w-reveal-target="toggle" aria-controls="my-content" type="button">Toggle</button>
+ *   <div id="my-content">CONTENT</div>
  * </section>
+ * ```
  */
 export class RevealController extends Controller<HTMLElement> {
   static classes = [
diff --git a/client/src/controllers/SlugController.ts b/client/src/controllers/SlugController.ts
index 03060d12f4..ad387af676 100644
--- a/client/src/controllers/SlugController.ts
+++ b/client/src/controllers/SlugController.ts
@@ -8,7 +8,9 @@ type SlugMethods = 'slugify' | 'urlify';
  * Adds ability to slugify the value of an input element.
  *
  * @example
+ * ```html
  * <input type="text" name="slug" data-controller="w-slug" data-action="blur->w-slug#slugify" />
+ * ```
  */
 export class SlugController extends Controller<HTMLInputElement> {
   static values = {
diff --git a/client/src/controllers/SubmitController.ts b/client/src/controllers/SubmitController.ts
index 36cf816497..c67471df65 100644
--- a/client/src/controllers/SubmitController.ts
+++ b/client/src/controllers/SubmitController.ts
@@ -3,14 +3,15 @@ import { Controller } from '@hotwired/stimulus';
 /**
  * Adds the ability for a field to trigger an automatic submission of its attached form.
  *
- * @example
- * // once any change is made to the below select field, the form will be auto submitted
+ * @example - Once any change is made to the below select field, the form will be auto submitted
+ * ```html
  * <form>
  *   <select name="order" data-controller="w-submit" data-action="change->w-submit#submit">
  *     <option value="A-Z">A to Z</option>
  *     <option value="Z-A">Z to A</option>
  *   </select>
  * </form>
+ * ```
  */
 export class SubmitController extends Controller<
   HTMLInputElement | HTMLSelectElement
diff --git a/client/src/controllers/SwapController.ts b/client/src/controllers/SwapController.ts
index 2d1fe7e8a9..39d68837aa 100644
--- a/client/src/controllers/SwapController.ts
+++ b/client/src/controllers/SwapController.ts
@@ -12,41 +12,46 @@ import { WAGTAIL_CONFIG } from '../config/wagtailConfig';
  * values.
  *
  * @example - A form that will update the results based on the form's input
- *  <div id="results"></div>
- *  <form
- *    data-controller="w-swap"
- *    data-action="input->w-swap#submitLazy"
- *    data-w-swap-src-value="path/to/search"
- *    data-w-swap-target-value="#results"
- *  >
- *  <input id="search" type="text" name="query" />
- *  <input id="filter" type="text" name="filter" />
+ * ```html
+ * <div id="results"></div>
+ * <form
+ *   data-controller="w-swap"
+ *   data-action="input->w-swap#submitLazy"
+ *   data-w-swap-src-value="path/to/search"
+ *   data-w-swap-target-value="#results"
+ * >
+ *   <input id="search" type="text" name="query" />
+ *   <input id="filter" type="text" name="filter" />
  * </form>
+ * ```
  *
  * @example - A single input that will update the results & the URL
- *  <div id="results"></div>
- *  <input
- *    id="search"
- *    type="text"
- *    name="q"
- *    data-controller="w-swap"
- *    data-action="input->w-swap#searchLazy"
- *    data-w-swap-src-value="path/to/search"
- *    data-w-swap-target-value="#listing-results"
- *  />
+ * ```html
+ * <div id="results"></div>
+ * <input
+ *   id="search"
+ *   type="text"
+ *   name="q"
+ *   data-controller="w-swap"
+ *   data-action="input->w-swap#searchLazy"
+ *   data-w-swap-src-value="path/to/search"
+ *   data-w-swap-target-value="#listing-results"
+ * />
+ * ```
  *
  * @example - A single button that will update the results
- *  <div id="results"></div>
- *  <button
- *    id="clear"
- *    data-controller="w-swap"
- *    data-action="input->w-swap#replaceLazy"
- *    data-w-swap-src-value="path/to/results/?type=bar"
- *    data-w-swap-target-value="#results"
- *  >
- *    Clear owner filter
- *  </button>
- *
+ * ```html
+ * <div id="results"></div>
+ * <button
+ *   id="clear"
+ *   data-controller="w-swap"
+ *   data-action="input->w-swap#replaceLazy"
+ *   data-w-swap-src-value="path/to/results/?type=bar"
+ *   data-w-swap-target-value="#results"
+ * >
+ *   Clear owner filter
+ * </button>
+ * ```
  */
 export class SwapController extends Controller<
   HTMLFormElement | HTMLInputElement | HTMLButtonElement
diff --git a/client/src/controllers/SyncController.ts b/client/src/controllers/SyncController.ts
index 779ab505f6..16e3a2effe 100644
--- a/client/src/controllers/SyncController.ts
+++ b/client/src/controllers/SyncController.ts
@@ -7,6 +7,7 @@ import { debounce } from '../utils/debounce';
  * or more targeted other inputs.
  *
  * @example
+ * ```html
  * <section>
  *   <input type="text" name="title" id="title" />
  *   <input
@@ -19,6 +20,7 @@ import { debounce } from '../utils/debounce';
  *     data-w-sync-target-value="#title"
  *   />
  * </section>
+ * ```
  */
 export class SyncController extends Controller<HTMLInputElement> {
   static values = {
diff --git a/client/src/controllers/TagController.ts b/client/src/controllers/TagController.ts
index 68b010c584..11bdfd2d82 100644
--- a/client/src/controllers/TagController.ts
+++ b/client/src/controllers/TagController.ts
@@ -15,10 +15,14 @@ declare global {
  * See https://github.com/aehlke/tag-it
  *
  * @example
+ * ```html
  * <input id="id_tags" type="text" name="tags" data-controller="w-tag" data-w-tag-url-value="/admin/tag-autocomplete/" />
+ * ```
  *
- * @example - with delay
+ * @example - With delay
+ * ```html
  * <input id="id_tags" type="text" name="tags" data-controller="w-tag" data-w-tag-delay-value="300" data-w-tag-url-value="/admin/tag-autocomplete/" />
+ * ```
  */
 export class TagController extends Controller {
   static values = {
diff --git a/client/src/controllers/TeleportController.ts b/client/src/controllers/TeleportController.ts
index a9b478dfd4..f61cecc2df 100644
--- a/client/src/controllers/TeleportController.ts
+++ b/client/src/controllers/TeleportController.ts
@@ -12,15 +12,17 @@ import { runInlineScripts } from '../utils/runInlineScripts';
  * Depending on location of the controlled element.
  *
  * @example
+ * ```html
  * <aside>
  *   <template
- *    data-controller="w-teleport"
- *    data-w-teleport-target-value="#other-location"
+ *     data-controller="w-teleport"
+ *     data-w-teleport-target-value="#other-location"
  *   >
- *    <div class="content-to-clone">Some content</div>
+ *     <div class="content-to-clone">Some content</div>
  *   </template>
  *   <div id="other-location"></div>
  * </aside>
+ * ```
  */
 export class TeleportController extends Controller<HTMLTemplateElement> {
   static values = {
diff --git a/client/src/controllers/TooltipController.ts b/client/src/controllers/TooltipController.ts
index 6ae255138b..7eaa2c92e4 100644
--- a/client/src/controllers/TooltipController.ts
+++ b/client/src/controllers/TooltipController.ts
@@ -30,9 +30,11 @@ export const hideTooltipOnEsc = {
  * A Tippy.js tooltip with simple popover content.
  *
  * @example
+ * ```html
  * <button type="button" data-controller="w-tooltip" data-w-tooltip-content-value="More detail here">
- *  A button with a tooltip
+ *   A button with a tooltip
  * </button>
+ * ```
  */
 export class TooltipController extends Controller<HTMLElement> {
   static values = {
diff --git a/client/src/controllers/UnsavedController.ts b/client/src/controllers/UnsavedController.ts
index 4d5832a221..63d860419b 100644
--- a/client/src/controllers/UnsavedController.ts
+++ b/client/src/controllers/UnsavedController.ts
@@ -21,6 +21,7 @@ const DEFAULT_DURATIONS = {
  * are about to move away from the page with potentially unsaved changes.
  *
  * @example - Warn the user when there are unsaved edits
+ * ```html
  * <form
  *   data-controller="w-unsaved"
  *   data-action="w-unsaved#submit beforeunload@window->w-unsaved#confirm change->w-unsaved#check"
@@ -29,8 +30,10 @@ const DEFAULT_DURATIONS = {
  *   <input type="text" value="something" />
  *   <button>Submit</submit>
  * </form>
+ * ```
  *
  * @example - Watch comments for changes in addition to edits (default is edits only)
+ * ```html
  * <form
  *   data-controller="w-unsaved"
  *   data-action="w-unsaved#submit beforeunload@window->w-unsaved#confirm change->w-unsaved#check"
@@ -40,8 +43,10 @@ const DEFAULT_DURATIONS = {
  *   <input type="text" value="something" />
  *   <button>Submit</submit>
  * </form>
+ * ```
  *
  * @example - Force the confirmation dialog
+ * ```html
  * <form
  *   data-controller="w-unsaved"
  *   data-action="w-unsaved#submit beforeunload@window->w-unsaved#confirm change->w-unsaved#check"
@@ -51,8 +56,10 @@ const DEFAULT_DURATIONS = {
  *   <input type="text" value="something" />
  *   <button>Submit</submit>
  * </form>
+ * ```
  *
  * @example - Force the confirmation dialog without watching for edits/comments
+ * ```html
  * <form
  *   data-controller="w-unsaved"
  *   data-action="w-unsaved#submit beforeunload@window->w-unsaved#confirm"
@@ -63,6 +70,7 @@ const DEFAULT_DURATIONS = {
  *   <input type="text" value="something" />
  *   <button>Submit</submit>
  * </form>
+ * ```
  */
 export class UnsavedController extends Controller<HTMLFormElement> {
   static values = {
diff --git a/client/src/controllers/UpgradeController.ts b/client/src/controllers/UpgradeController.ts
index 487dd0640a..2d0087996d 100644
--- a/client/src/controllers/UpgradeController.ts
+++ b/client/src/controllers/UpgradeController.ts
@@ -17,7 +17,7 @@ interface LatestVersionData extends VersionData {
  * is out of date.
  *
  * Expected JSON payload:
- *
+ * ```json
  * {
  *     "version": "2.15.2",
  *     "url":     "https://docs.wagtail.io/en/stable/releases/2.15.2.html",
@@ -28,6 +28,18 @@ interface LatestVersionData extends VersionData {
  *         "minorUrl": "https://docs.wagtail.io/en/stable/releases/2.12.html"
  *     }
  * }
+ * ```
+ *
+ * @example
+ * ```html
+ * <div
+ *   data-controller="w-upgrade"
+ *   data-w-upgrade-current-version-value="6.3.1"
+ *   data-w-upgrade-url-value="https://path.to/latest.txt"
+ * >
+ *   <p>A new version of Wagtail is available!</p>
+ * </div>
+ * ```
  */
 export class UpgradeController extends Controller<HTMLElement> {
   static targets = ['latestVersion', 'link', 'dismiss'];
diff --git a/client/src/controllers/ZoneController.ts b/client/src/controllers/ZoneController.ts
index 2ee7edc8af..afe2af0ebe 100644
--- a/client/src/controllers/ZoneController.ts
+++ b/client/src/controllers/ZoneController.ts
@@ -30,7 +30,7 @@ enum ZoneMode {
  *   data-w-zone-active-class="public"
  *   data-w-zone-inactive-class="private"
  *   data-w-zone-switch-key-value="isPublic"
- *>
+ * >
  *  Content
  * </div>
  * ```