{"schemaVersion":1,"title":"Rich article components","url":"https://appgram.github.io/docsy/guides/tutorials/rich-articles","markdownUrl":"https://appgram.github.io/docsy/format-md/guides/tutorials/rich-articles","jsonUrl":"https://appgram.github.io/docsy/agent/pages/guides/tutorials/rich-articles.json","version":"current","locale":"en","markdown":"# Rich article components\n\nWrite callouts, steps, synchronized tabs, accordions, code groups, and reusable snippets in Markdown.\n\nWritten by: [nedimf](https://github.com/nedimf), [AppGram](https://appgram.dev)\n\nDocsy articles support declarative Markdown components. Product configuration stays in YAML; the article body stays in Markdown. No React, MDX, remote fonts, or hosted editor is required.\n\n## Callouts\n\n> Configuration belongs in YAML\n>\n> Keep product identity, navigation, sources, and permissions in `docsy.config.yaml`. Write the explanation here, in Markdown.\n\n> Validate before you publish\n>\n> Run `npm run validate` to catch broken links, invalid components, and ingestion errors before they reach your readers.\n\n> Keep secrets out of source\n>\n> Read API credentials from the server environment. Never commit private tokens to YAML or publish them in an example.\n\n> Static files cannot enforce permissions\n>\n> Use the Node or Bun server for locked documentation. A public static host cannot protect private article content with a browser-only gate.\n\nEach kind has its own icon and restrained accent, with readable surfaces in both themes. The title explains the situation; the body tells the reader what to do. Color is not the only way to distinguish them.\n\nWrite a callout like this:\n\n```md\n:::warning[Keep secrets out of source]\nRead API credentials from the server environment, not committed YAML.\n:::\n```\n\n## Numbered steps\n\n> 1. **Generate a project.** Start with the editable Docsy interface.\n>\n> 2. **Configure your sources.** Register Markdown, API contracts, and SDK metadata in YAML.\n>\n> 3. **Validate and publish.** Review the built result before deployment.\n\nWrap a Markdown ordered list in `:::steps` and close it with `:::`. Nested paragraphs and code fences are supported inside list items.\n\n## Synchronized tabs\n\nChoose a package manager. Other tab groups with the same `sync` key remember the same label across pages, using local storage only.\n\n> > npm\n> >\n> > ```bash\n> > npm run validate\n> > npm run build\n> > ```\n>\n> > pnpm\n> >\n> > ```bash\n> > pnpm validate\n> > pnpm build\n> > ```\n\nThe outer group uses four colons so that its three-colon tab children can nest. Tabs support arrow keys, Home, End, focus indicators, and a readable all-panels fallback without JavaScript.\n\n````md\n::::tabs{sync=\"package-manager\"}\n:::tab[npm]\n```bash\nnpm run build\n```\n:::\n:::tab[pnpm]\n```bash\npnpm build\n```\n:::\n::::\n````\n\n## Code groups\n\nUse `:::code-group` around fenced code blocks to create language tabs. The fence's metadata, or language when metadata is absent, supplies each tab label.\n\nFenced code is highlighted at build time, including inside groups, tabs, callouts, and snippets. Code cards show the language's local logo, retain an accessible language label, and copy plain source code. The portal's light/dark toggle changes token colors automatically; configure palettes with `theme.code.lightTheme` and `theme.code.darkTheme`. The **Default UI** guide documents code appearance and logo overrides.\n\n> ```javascript JavaScript\n> console.log('Documentation owned by your team.');\n> ```\n>\n> ```python Python\n> print('Documentation owned by your team.')\n> ```\n\n## Expandable explanations\n\n> What happens without JavaScript?\n>\n> All tab content stays visible, steps remain readable, and accordions use the browser's native details element. Search indexes every tab's content, not only the currently selected panel.\n\n## Reusable snippets\n\nRegister named local Markdown files in YAML:\n\n```yaml\ncontent:\n  snippets:\n    publishing: content/snippets/publishing-checklist.md\n```\n\nThen insert `::include{src=\"publishing\"}` on its own line. The result below is shared content:\n\n* Validate the configured sources, internal links, and heading anchors.\n* Build the exact version and language combinations you intend to publish.\n* Review examples and permission rules before deploying.\n\nIncludes are expanded in rendered articles, search, JSON documents, and Markdown exports. Unknown names, includes outside the project, circular references, and more than ten nested includes stop validation. Include directives inside fenced examples are not expanded.\n\n## draw.io diagrams\n\nUse SVG or PNG exports for technical architecture diagrams. Register the preview and optional editable `.drawio` source in `content.diagrams`, then embed `::drawio{src=\"architecture\"}`. MDX supports `<Drawio src=\"architecture\" />`. Diagrams share the fullscreen image viewer and remain protected with their article.\n\nSee [draw.io diagrams](/guides/tutorials/drawio-diagrams) for a working example, YAML, source downloads, and supported export boundaries.\n\n## Images and videos\n\nArticle images open in a fullscreen viewer when clicked. Videos keep their native inline controls and get an **Expand video** button. The viewer follows the portal's light/dark theme and offers image zoom, captions, previous/next controls, and an original-file link. Escape closes it and returns focus to the trigger. Opening a video pauses the inline player and preserves its time position without starting audio automatically.\n\nScroll or pinch to zoom around the pointer, then drag to pan. The toolbar shows the actual zoom percentage and provides minus, plus, and fit/actual-size controls. Double-click (or double-tap) toggles fit and actual size; zoom is bounded between fit and 800%. Keyboard shortcuts: `+`/`-` zoom, `0` or `f` fits the image, and `1` selects actual size. Arrow keys pan while zoomed, and navigate media while fitted. Video controls retain their native seeking keys. Zoom resets when moving to another item; resizing keeps a fitted image fitted.\n\nConfigure this independently of the article component list:\n\n```yaml\ncontent:\n  media:\n    enabled: true\n    images: true\n    videos: true\n```\n\nSet `enabled: false` to disable the viewer, or turn off only `images` or `videos`. These settings default to `true`, including in generated projects. Without JavaScript, images and video controls remain ordinary page content.\n\nMarkdown images work normally. For native video and captions, use HTML in Markdown or the same elements in declarative MDX:\n\n```mdx\n<figure>\n  <video controls playsInline preload=\"metadata\" poster=\"/assets/demo-poster.png\" aria-label=\"Product walkthrough\">\n    <source src=\"/assets/demo.webm\" type=\"video/webm\" />\n    <track src=\"/assets/demo.en.vtt\" kind=\"captions\" srcLang=\"en\" label=\"English\" default />\n  </video>\n  <figcaption>A short product walkthrough.</figcaption>\n</figure>\n```\n\nAdd these files to `public/assets/` for public media; MDX rebases the root-relative paths above to `site.basePath`. In raw Markdown HTML, write URLs relative to the served page or include your configured base path yourself. Raw HTML uses lowercase attributes such as `playsinline` and `srclang`, rather than MDX's `playsInline` and `srcLang`. Do not put confidential media in `public/`: those files bypass access gates.\n\n`figcaption` supplies the viewer caption, falling back to the image's title or alt text, or the video's accessible label. Add `data-docsy-media=\"off\"` to a media element or its surrounding figure to leave it inline only. Linked images retain their original link behavior; decorative icons and code-language logos are excluded. Source-owned layouts can opt an image or video inside `.docs-content` into the viewer with `data-docsy-media=\"true\"`.\n\nThis is a native HTML video player, not a YouTube/Vimeo iframe integration. No external player scripts, fonts or analytics are loaded.\n\n## Choose supported components\n\nThe default is all supported components. Restrict the set for a project in YAML:\n\n```yaml\ncontent:\n  components: [note, tip, warning, danger, steps, tabs, accordion, code-group, include]\n```\n\n`tab` is an internal child of `tabs`, not a standalone component. Unknown components, orphan tabs, disabled components, and invalid code-group contents fail validation. Rendered colors use the existing theme tokens; component styling lives in `src/styles/article-components.css`.\n\n","contentLocale":"en","isFallback":false,"authorship":{"authors":[{"name":"nedimf","kind":"human","github":"nedimf","avatar":"/docsy/assets/authors/nedimf.png","role":"AppGram","id":"nedimf","url":"https://github.com/nedimf"},{"name":"AppGram","kind":"organization","github":"AppGram","url":"https://appgram.dev","avatar":"/docsy/assets/ag-logo.svg","id":"appgram"}],"contributors":[],"reviewedBy":[]},"editUrl":"https://github.com/AppGram/docsy/edit/main/content/tutorials/rich-articles.md"}