Shortcodes & Styling Guide

Complete reference for Doco shortcodes, Markdown styling, and how to prompt Claude to write well-formatted documents

Prompt Template for Claude

When asking Claude to write or convert documents for Doco, paste the following instruction block into your prompt. This teaches Claude all available formatting tools so it produces rich, well-structured pages on the first try.

Copy this prompt block

You are writing a Markdown document for a Hugo documentation site called Doco. The site supports standard GitHub-Flavored Markdown plus the following custom shortcodes. Use them liberally to make the document scannable, visually structured, and easy to navigate.

Hints — colored callout boxes. Use for tips, warnings, and critical notes.


Tip or note content here.
Caution or caveat content here.
Critical warning or breaking change here.

Details — collapsible sections. Use for supplementary info, FAQs, or lengthy content that shouldn’t clutter the main flow.

Click to expand Hidden content here. Supports full Markdown.

Tabs — switchable panels. Use when showing the same concept across platforms, languages, or config formats.

Content for first tab.
Content for second tab.

Columns — side-by-side layout (stacks on mobile). Use for comparisons, before/after, or splitting related content.

Left content.
Right content.

Style guidelines:

  • Use h2 (##) for major sections and h3 (###) for subsections — these appear in the sidebar TOC
  • Use hints instead of blockquotes for callouts
  • Use details for FAQ items, troubleshooting steps, or optional deep-dives
  • Use tabs whenever content varies by platform, language, tool, or version
  • Use columns for comparisons or to display related items side-by-side
  • Shortcodes can be nested (hints inside columns, tabs inside details, etc.)
  • Use fenced code blocks with language tags for syntax highlighting
  • Use tables for structured data with multiple fields
  • Keep paragraphs short — prefer lists and headings for scannability

Shortcode Reference

Hints

Colored callout boxes with a left border. Three variants based on severity.

Info — Use for tips, notes, helpful context, or “good to know” asides. This is the default you should reach for most often.
Warning — Use for caveats, deprecation notices, things that might cause confusion, or “watch out” moments.
Danger — Use for breaking changes, destructive operations, security concerns, or anything that could cause data loss.

Hints support full Markdown inside — paragraphs, lists, code, links, bold, everything:

Environment variables must be set before running the server:

  • DATABASE_URL — connection string for Postgres
  • SECRET_KEY — used for session signing
  • DEBUG — set to true in development only
export DATABASE_URL="postgres://localhost:5432/myapp"
export SECRET_KEY="change-me"

See the configuration docs for the full list.

Deprecation notice: The v1/auth endpoint will be removed in the next major release.

Old endpointNew endpointMigration
POST /v1/auth/loginPOST /v2/sessionUpdate path + body format
GET /v1/auth/meGET /v2/user/profileUpdate path only

This action is irreversible. Running DROP TABLE will permanently delete all data in the table. Always create a backup first:

pg_dump -t my_table mydb > backup.sql

Details

Collapsible sections using the HTML <details> element. The title goes in quotes after the shortcode name.

Basic exampleThis content is hidden by default. Click the summary to reveal it. Useful for keeping pages clean while still providing depth.

Great for FAQs:

How does password protection work?

Doco uses client-side SHA-256 hash comparison. Passwords are never stored in plaintext — only their hashes appear in the front matter. The protect.js script compares the user’s input against the hash using the Web Crypto API.

Unlock state is cached in sessionStorage, so users only enter the password once per browser session.

Can I use a different hash algorithm?Not currently. The system is hardcoded to SHA-256 via the Web Crypto API. If you need something different, you’d modify assets/js/protect.js.
What if I forget a project password?

Passwords aren’t stored anywhere — only hashes. If you lose the password, generate a new hash and update the _index.md front matter:

printf '%s' 'new-password' | shasum -a 256 | cut -d' ' -f1

Replace the passwordHash value in both the cascade.params and params blocks.

Great for troubleshooting:

Hugo build fails with 'template not found'

This usually means a layout file is missing or misnamed. Check that:

  1. The file is in layouts/_default/ or layouts/partials/
  2. The filename matches exactly (Hugo is case-sensitive)
  3. You haven’t accidentally nested it in an extra subdirectory
# List all layout files to verify
find layouts -type f -name "*.html"
Search returns no results after deploy

Pagefind runs as a post-build step. If search isn’t working:

  1. Check the GitHub Actions log for the “Index with Pagefind” step
  2. Verify that public/pagefind/ was created before the upload step
  3. Ensure data-pagefind-body is present on your content divs

In local dev (hugo server), search won’t return results — that’s expected. To test locally, run:

mise exec -- hugo && npx -y pagefind --site public --serve

Tabs

Switchable tabbed panels. Wrap tab panels inside a tabs container. Each tab gets a name in quotes.

Platform-specific instructions — the most common use case:

Install with Homebrew:

brew install hugo

Verify the installation:

hugo version

Install with your package manager:

# Ubuntu/Debian
sudo apt install hugo

# Arch
sudo pacman -S hugo

# Snap (any distro)
sudo snap install hugo

Install with Chocolatey or Scoop:

# Chocolatey
choco install hugo-extended

# Scoop
scoop install hugo-extended

Language/framework comparisons:

import hashlib

password = "my-secret"
hash = hashlib.sha256(password.encode()).hexdigest()
print(hash)
const encoder = new TextEncoder();
const data = encoder.encode("my-secret");
const hash = await crypto.subtle.digest("SHA-256", data);
const hex = Array.from(new Uint8Array(hash))
  .map(b => b.toString(16).padStart(2, "0"))
  .join("");
console.log(hex);
printf '%s' 'my-secret' | shasum -a 256 | cut -d' ' -f1

Configuration format comparisons:

baseURL = "https://doco.example.com"
title = "My Docs"

[params]
  masterPasswordHash = "abc123..."

[markup.goldmark.renderer]
  unsafe = true

[markup.tableOfContents]
  startLevel = 2
  endLevel = 3
baseURL: "https://doco.example.com"
title: "My Docs"

params:
  masterPasswordHash: "abc123..."

markup:
  goldmark:
    renderer:
      unsafe: true
  tableOfContents:
    startLevel: 2
    endLevel: 3
{
  "baseURL": "https://doco.example.com",
  "title": "My Docs",
  "params": {
    "masterPasswordHash": "abc123..."
  },
  "markup": {
    "goldmark": {
      "renderer": { "unsafe": true }
    },
    "tableOfContents": {
      "startLevel": 2,
      "endLevel": 3
    }
  }
}

API response examples:

{
  "status": 200,
  "data": {
    "id": "usr_abc123",
    "email": "user@example.com",
    "role": "admin"
  }
}
{
  "status": 401,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or expired token"
  }
}

Columns

Responsive multi-column grid. Columns sit side-by-side on desktop and stack vertically on mobile.

Two columns — comparisons, pros/cons, before/after:

Do

  • Use h2/h3 headings for TOC structure
  • Use hints for callouts instead of blockquotes
  • Use tabs for platform-specific content
  • Use details to hide lengthy supplementary info
  • Keep paragraphs short
  • Use code fences with language tags

Don’t

  • Use h1 headings in content (reserved for the page title)
  • Use raw HTML when a shortcode exists
  • Put critical info inside collapsed details
  • Create tabs with only one tab
  • Write walls of unbroken text
  • Leave code blocks without a language tag

Three columns — steps, features, or categories:

1. Create

Create a new folder under content/ with an _index.md that sets up the project and password cascade.

2. Write

Add .md files to the folder. Use shortcodes, headings, code blocks, and tables to structure the content.

3. Ship

Push to main. GitHub Actions builds, indexes for search, and deploys to Pages automatically.

Columns with mixed content:

Endpoint

POST /api/v2/documents

Headers

HeaderValue
AuthorizationBearer <token>
Content-Typeapplication/json

Request body

{
  "title": "My Document",
  "content": "# Hello\n\nWorld.",
  "tags": ["guide", "v2"]
}
The content field accepts raw Markdown.

Combining Shortcodes

Shortcodes nest freely. Here are patterns that work well together.

Hints inside columns

Development — Uses hot-reload, verbose logging, and an in-memory database. No authentication required.
Production — Minified assets, structured logging, Postgres required. All endpoints authenticated.

Tabs inside details

Database migration examples
CREATE TABLE users (
  id         SERIAL PRIMARY KEY,
  email      VARCHAR(255) NOT NULL UNIQUE,
  name       VARCHAR(255),
  created_at TIMESTAMP DEFAULT NOW()
);

CREATE INDEX idx_users_email ON users(email);
DROP INDEX IF EXISTS idx_users_email;
DROP TABLE IF EXISTS users;

Details inside columns

Frontend

Tech stack
  • React 18 with TypeScript
  • Vite for bundling
  • TanStack Query for data fetching
  • Tailwind CSS for styling
Dev server
cd frontend
npm install
npm run dev

Runs on http://localhost:5173

Backend

Tech stack
  • Go 1.22
  • Chi router
  • sqlc for type-safe SQL
  • Postgres 16
Dev server
cd backend
go run ./cmd/server

# or with live reload
air

Runs on http://localhost:8080

Full example — feature documentation pattern

This is what a well-structured feature doc looks like using all available tools:

New in v2.4 — Webhook support was added in version 2.4.0. If you’re on an earlier version, see the changelog for upgrade instructions.

Webhooks allow your application to receive real-time notifications when events occur. Instead of polling the API, you register a URL and we send POST requests to it.

Register a webhook endpoint in your dashboard or via the API:

curl -X POST https://api.example.com/v2/webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/hooks/incoming",
    "events": ["document.created", "document.updated"]
  }'
Your endpoint must respond with a 200 status within 5 seconds or the delivery will be retried.

Every webhook delivery includes a JSON body:

{
  "event": "document.created",
  "timestamp": "2026-02-18T12:00:00Z",
  "data": {
    "id": "doc_xyz",
    "title": "New Document",
    "created_by": "usr_abc"
  }
}
FieldTypeDescription
eventstringThe event type that triggered the webhook
timestampstringISO 8601 timestamp of the event
dataobjectEvent-specific payload

All deliveries include an X-Signature-256 header. Verify it to ensure the request came from us:

import hmac, hashlib

def verify_signature(payload, signature, secret):
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)
Never skip verification in production. Without it, any party could send fake events to your endpoint.
Supported events
EventTrigger
document.createdA new document is created
document.updatedA document’s content or metadata changes
document.deletedA document is permanently deleted
user.invitedA new user is invited to the workspace
user.removedA user is removed from the workspace
Retry policy

Failed deliveries are retried with exponential backoff:

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry12 hours

After 5 failed attempts, the webhook is disabled and you’ll receive an email notification.

You can manually retry failed deliveries from the dashboard or re-enable a disabled webhook via the API.

Standard Markdown Features

Beyond shortcodes, these standard Markdown features are all styled and ready to use.

Tables

FeatureStatusNotes
HintsStableThree variants: info, warning, danger
DetailsStableCollapsible with animated arrow
TabsStableAuto-wires click handlers via JS
ColumnsStableResponsive grid, stacks on mobile
SearchStablePagefind, indexed at build time

Code blocks

Inline code like variable_name and fenced blocks with syntax highlighting:

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, Doco!")
    })
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Lists

Ordered and unordered, including nested:

  1. First step
    • Sub-item with detail
    • Another sub-item
  2. Second step
  3. Third step

Blockquotes

Blockquotes still work for attributable quotes or cited material. For callouts, prefer hints instead — they’re more visually distinct.

Images

Images are supported with standard Markdown syntax and render with rounded corners:

![Alt text](image-url.png)

Horizontal rules

Use --- to create visual section breaks between major topics (as seen throughout this page).