Writing articles
The TipTap rich-text editor, what it supports, and what gets sanitized out.
Articles are written in a rich-text editor based on TipTap / ProseMirror. The toolbar covers the formatting you actually need; the underlying HTML is sanitized before save so you can't accidentally save a <script> tag, even if you paste one in.
The toolbar
- Bold, italic, strikethrough, inline code
- Headings — H1, H2, H3 (the article title is the document
<h1>, so use H2 as your top section heading) - Bullet list, numbered list, blockquote
- Code block — fenced code, no language coloring (for now)
- Link — opens in a new tab with
rel="noopener noreferrer"automatically - Horizontal rule
- Undo / redo
That's it. No font picker, no color picker, no font size. The design is opinionated on purpose — KB articles read better when authors don't have to make typographic choices.
What gets stripped on save
We run every save through HTMLPurifier with a strict profile:
<script>,<iframe>,<style>, inlinestyle="…",onClick="…"— gone.- Any tag not on the allowlist — gone.
- URL schemes other than http(s), mailto, tel — gone.
Pasting from Word / Google Docs is fine; their formatting noise gets cleaned. Pasting from a phishing page can't sneak something past the sanitizer.
Fields beyond the body
- Title — the article's
<h1>and the page<title>tag. - Slug — URL path. Auto-generated from the title; editable. Don't change a published article's slug without redirecting from the old one.
- Meta description — under 320 characters. Used for
<meta name="description">and Open Graph. Skip and we'll auto-extract from the body. - Tags — comma-separated. See Tags and featured.
- Category — required for the article to be browsable. Uncategorized articles still get a URL but don't show in category lists.
Saving
The editor saves on submit only — there's no autosave today. If your browser crashes mid-write, you lose what wasn't saved. Save early, save often, especially before reformatting.
Editing a published article
Just edit and save. Changes go live immediately — no draft / preview step. The updated_at timestamp is what appears as "Last updated" on the visitor side.