MDX content
Posts, pages, your own content types and sections can all be written in MDX: Markdown plus HTML and the components your site allows.
Where MDX is used
Section titled “Where MDX is used”- Posts and pages in the starter are MDX collections (
format: "mdx"inwuppy.config.mjs). New entries are saved as.mdx. Existing.mdfiles keep working and stay.mduntil a component is inserted, when Wuppy promotes that entry to.mdx; the same collection can hold both. - Content types you create in the admin are MDX by default. You can still pick Markdown.
- Sections store their body as MDX.
- Widgets: a custom widget’s body is MDX; an HTML widget gets the raw-HTML checks below before it is saved (and is still sanitised when shown). Text widgets are shown as plain text.
What authors may write
Section titled “What authors may write”-
Markdown, HTML elements and the components listed in
componentsinwuppy.config.mjs:export default { components: ["Callout", "YouTube"], collections: [/* … */] }; -
Component props are plain values only: text, numbers,
true/false, lists and objects written as JSON.<Callout tone="info" items={["a", "b"]}>is fine.
What is refused
Section titled “What is refused”Saving is refused with the reason (HTTP 422, DISALLOWED_CONTENT) when a body contains:
importorexportlines.- JavaScript expressions such as
{process.env.SECRET}ortitle={user.name}. A comment,{/* … */}, is allowed. - Components that are not in the allowed list, and member names such as
<a.b>. - Spread props (
{...props}). - Event handlers (
onclick,onError…), Astro directives (set:html,is:raw,client:*),dangerouslySetInnerHTMLandsrcdoc. script,style,iframe,object,embed,form,link,meta,baseand similar tags.javascript:,vbscript:anddata:links.data:images (PNG, JPEG, GIF, WebP, AVIF) are allowed.- MDX that does not parse. The error shows the line, so the site build never breaks on it.
Markdown (.md) bodies are checked for the same dangerous tags, attributes and links.
The body is checked with the same parser Astro uses. Code inside code blocks is text and is never checked.
On the site
Section titled “On the site”-
The starter has
@astrojs/mdxinastro.config.mjsand loads**/*.{md,mdx}. For an existing Astro projectwuppycms initdoes the same: it addsmdx()and@astrojs/mdx, and widenspattern: "**/*.md"globs to**/*.{md,mdx}. -
Theme components are mapped automatically: Wuppy adds a
componentsmap to<Content />in the theme’s pages, so a theme’ssrc/components/*.astrofiles can be inserted from Add → Components without an import line. -
For a site’s own components, add their names to
componentsinwuppy.config.mjsand pass them when you render an entry:<Content components={{ Callout }} />. -
An MDX entry edited in the admin shows at once, without a rebuild. It is compiled with the site’s Markdown settings: headings get the same ids and
headingslist as in the build, code blocks the same highlighting. -
Render a section (or custom widget) body with
mdxContentfromwuppycms/mdx. It runs the same checks again before rendering and returns whatrender()does,{ Content, headings }:---import { getSection } from "wuppycms";import { mdxContent } from "wuppycms/mdx";import Callout from "../components/Callout.astro";const section = await getSection("cta");const { Content: Body } = section ? await mdxContent(section.body) : {};---{Body && <Body components={{ Callout }} />}