# Markdown in responses is rendered

- **Pattern:** `ab-000136` (`ai-chat-visibility.response-display.markdown-rendering`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000136
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000136)

## Why it matters

AI models produce markdown-formatted output by default: bold, italics, bulleted lists, headers, and inline code are the native vocabulary of modern LLM responses. Rendering that output as plain text means users see raw `**asterisks**` and `## hashes` cluttering every answer, destroying readability and forcing users to mentally parse formatting tokens. This also degrades accessibility by collapsing semantic structure into an undifferentiated wall of text, failing the intent of WCAG 2.2 SC 1.3.1 (Info and Relationships).

## Severity rationale

High because unreadable output is functionally broken even when the model response is technically correct.

## Remediation

Install a markdown renderer and pipe AI message content through it in your message component at `src/components/chat/MessageBubble.tsx`. Pair it with Tailwind's typography plugin for clean default styling, and never render raw HTML from AI output without sanitization.

```tsx
import ReactMarkdown from 'react-markdown';
<div className="prose dark:prose-invert">
  <ReactMarkdown>{message.content}</ReactMarkdown>
</div>
```

## Detection

- **ID:** `markdown-rendering`
- **Severity:** `high`
- **What to look for:** Find where AI message content is displayed in the UI. Count all message rendering locations and for each classify whether content is rendered as plain text (wrapping message content in a plain paragraph) or passed through a markdown renderer. Look for `react-markdown`, `marked`, `remark`, `micromark`, or custom markdown parsers in `package.json`. Check whether markdown syntax would render as formatted HTML or appear as raw asterisks and hashes.
- **Pass criteria:** AI response content is rendered through a markdown parser in at least 1 rendering location. Bold, italic, headers, unordered and ordered lists, and inline code appear as formatted HTML, not raw markdown syntax.
- **Fail criteria:** Response content is rendered as plain text without markdown processing. Users see raw `**bold**` instead of formatted bold text.
- **Do NOT pass when:** A markdown library is installed but the message component does not use it — having `react-markdown` in `package.json` without importing it in the message renderer does not count as pass.
- **Skip (N/A) when:** The application is documented as a non-markdown interface (e.g., a pure voice assistant or structured-data-only output). Signal: no markdown-related dependencies and response display is deliberately plain text.
- **Detail on fail:** `"Message content rendered as plain text — no markdown processor found in dependencies; users see raw markdown syntax"`
- **Remediation:** Add `react-markdown` to your project. In your message component at `src/components/chat/MessageBubble.tsx` (or equivalent), wrap content:

  ```tsx
  import ReactMarkdown from 'react-markdown';
  <div className="prose dark:prose-invert">
    <ReactMarkdown>{message.content}</ReactMarkdown>
  </div>
  ```

  If using Tailwind, the `@tailwindcss/typography` plugin provides clean markdown styling via the `prose` class. Avoid rendering raw HTML from AI output without sanitization.
- **Cross-reference:** For a deeper analysis of accessible content rendering, the Accessibility Fundamentals Audit covers heading hierarchy and semantic HTML in detail.

## External references

- wcag 1.3.1

Taxons: user-experience

HTML version: https://auditbuffet.com/patterns/ab-000136
