Writing Accessible Markdown

Reviewed & published by Brayan K

By the end of this lesson you'll write Markdown that everyone can use — a logical heading outline, descriptive links, meaningful image alt text, proper table headers, and structure that screen readers can convey faithfully.

Part of the free Markdown course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn

💡 Real-World Analogy

Accessible Markdown is like reading a document aloud to a friend over the phone. Your friend can't see the page, so "click here" or "look at this" tells them nothing — you'd naturally say "visit the download page". You'd describe a chart instead of saying "nice picture", and you'd read section titles in order so they can follow along. A screen reader is that listener; writing with structure and descriptive words means it can pass on everything a sighted reader sees.

1. A Logical Heading Hierarchy

Headings aren't just big text — they form the outline screen reader users navigate by, jumping from heading to heading. Two rules keep that outline meaningful: use exactly one H1 as the page's single title, and don't skip levels. Go # then ## then ### in order; jumping from an H2 straight to an H4 leaves a gap that breaks the structure.

# Page Title          (one H1: the page's single top-level title)

## Getting Started     (H2: a major section)

### Install            (H3: a subsection of Getting Started)

### Configure          (H3: another subsection)

## Troubleshooting     (back to H2: a new major section)

The outline it creates

A screen reader can jump between these levels to scan the page.

🎯 Your Turn #1: a clean heading outline

Fill in the blanks with the right number of # characters so the program prints one H1, then an H2, then an H3 — no skipped levels.

// 🎯 YOUR TURN — build a correct heading hierarchy.
// Use exactly ONE H1, then go in order (H2, then H3) without skipping.
// Fill in each ___ with the right number of # characters.

const h1 = "___";   // 👉 one # for the single page title
const h2 = "___";   // 👉 two ## for a major section
const h3 = "___";   // 👉 three ### for a subsection of that section

console.log(h1 + " User Guide");
console.log(h2 + " Installation");
console.log(h3 + " Requirements");

// ✅ Expected printed source:
//    # User Guide
//    ## Installation
//    ### Requirements
//
// One H1, then H2, then H3 — a clean outline a screen reader can follow.

2. Descriptive Link Text

Many screen reader users pull up a list of all links on a page to navigate. If every link says "click here" or "this", that list is useless. Make link text describe its destination so it stands on its own: [setup steps](setup.md), not "for the setup steps, click here". Good link text helps everyone — it's also clearer for sighted readers scanning the page.

Bad  (vague out of context):
For the setup steps, [click here](setup.md).

Good (descriptive, makes sense alone):
Read the [setup steps](setup.md).

As a links list (sketch)

Out of context, which is useful?

3. Image Alt Text

Every meaningful image needs alt text — the text in ![alt](url) — that conveys what the image shows to someone who can't see it. Describe the meaning, not the file: "Bar chart: sales doubled from Q1 to Q2" beats "chart.png". For purely decorative images (dividers, spacers) use empty alt ![](divider.png) so screen readers skip them rather than announcing a useless filename.

Meaningful image (describe its content):
![Bar chart: sales doubled from Q1 to Q2](sales.png)

Decorative image (empty alt so it is skipped):
![](divider.png)

What a screen reader announces

✓ "Image: Bar chart: sales doubled from Q1 to Q2"

✓ (decorative image, with empty alt) — skipped silently

A missing alt would make some readers announce the filename instead, which is just noise.

Here's a worked example that prints accessible Markdown source. Run it, read each printed line, then notice how the structure, one H1, ordered levels, descriptive links, and real alt text, is what makes it usable for everyone.

## One H1, then ordered levels
# Quarterly Report
## Summary
### Highlights

## Descriptive link text
See the [full results](results.md).

## Alt text that conveys meaning
![Line chart: revenue rising each month](revenue.png)
![](spacer.png)

<!-- ✅ Expected result, rendered:
     h2  -> text: One H1, then ordered levels
     h1  -> count: 1
     h2  -> count: 4
     h3  -> count: 1
     p   -> count: 2
     a   -> count: 1
     img -> count: 2
-->

🎯 Your Turn #2: descriptive link and alt text

Fill in the blanks so the program prints a link with descriptive text and an image with meaningful alt text. Avoid "click here" and avoid empty alt for a meaningful image.

// 🎯 YOUR TURN — write DESCRIPTIVE link text and ALT text.
// Link text should make sense on its own; alt text should convey the
// image's meaning. Fill in each ___.

const linkText = "___";   // 👉 describe the destination, e.g. download page
const altText  = "___";   // 👉 describe the image, e.g. Screenshot of the app

console.log("Visit the [" + linkText + "](download.html).");
console.log("![" + altText + "](app.png)");

// ✅ Expected printed source (example):
//    Visit the [download page](download.html).
//    ![Screenshot of the app](app.png)
//
// Avoid "click here" and avoid empty alt for a meaningful image.

4. Table Headers and Honest Formatting

Give every table a clear header row so assistive tech can associate each data cell with its column — it can announce "Capital: Paris" rather than a lone "Paris". And never rely on formatting alone to carry meaning: if "items in bold are required", a user who can't perceive the bold misses it entirely. State the meaning in words (mark required items with the word "required") so it survives without the styling.

| Country | Capital  |
|---------|----------|
| France  | Paris    |
| Japan   | Tokyo    |

The header row (Country, Capital) lets a screen reader announce
each cell with its column name, e.g. "Capital: Paris".

Why the header row matters

CountryCapital
FranceParis
JapanTokyo

Each cell is announced with its column name, e.g. "Capital: Paris".

Common Errors (and the fix)

📋 Quick Reference — Accessibility

DoInstead of
One H1, ordered levelsSeveral H1s or skipped levels
[setup steps](setup.md)[click here](setup.md)
![Chart: sales doubled](s.png)![](s.png) for a meaningful image
![](divider.png) for decoration![decorative line](divider.png)
Table with a header rowA table with no header
"required" stated in wordsMeaning shown by bold alone

Mini-Challenge: An Accessible Mini-Document

No blanks this time — just a brief and an outline. Use console.log to print the source for a short page with one H1, ordered H2/H3 sections, a descriptive link, a meaningful image with alt text, and a small table with a header row.

// 🎯 MINI-CHALLENGE: print an accessible mini-document.
// Build (with console.log) the SOURCE for a short page that includes:
//   1. Exactly ONE H1 title
//   2. Two H2 sections, and one H3 under the first (no skipped levels)
//   3. One link with DESCRIPTIVE text (not "click here")
//   4. One meaningful image with ALT text that conveys its content
//   5. A small table WITH a header row
//
// ✅ The result should read as a clean outline with descriptive links,
//    real alt text, and a table whose header row labels the columns.

// your code here

Pro Tips

Frequently Asked Questions

Q: Does Markdown become accessible automatically?

Markdown produces real HTML headings, lists, and links, which is a great start. But meaning depends on you: descriptive link text, alt text, header rows, and a correct heading order.

Q: When should alt text be empty?

Only when the image is purely decorative and conveys no information. Empty alt tells screen readers to skip it; a meaningful image always needs descriptive alt.

Q: Is it really a problem to skip a heading level?

Yes. Users who navigate by headings rely on the order; a gap (H2 to H4) breaks the outline and makes the structure confusing.

Q: How do I emphasise something accessibly?

Use emphasis for visual weight, but also make the meaning explicit in words, so it isn't lost for anyone who can't perceive the styling.

Lesson Complete — and you've finished the course! 🎉

Where to go next: revisit the course overview to review earlier lessons, then apply these habits to a real README or docs site. Congratulations on completing the Markdown course! 📝

Practice quiz

How many top-level (H1) headings should a page normally have?

  • Exactly one
  • As many as you like
  • At least three
  • Zero

Answer: Exactly one. A single H1 gives the page one clear title; screen readers and outlines rely on that one top-level heading.

Why should you avoid skipping heading levels (for example H2 to H4)?

  • It hides the text
  • It changes the font colour
  • It breaks the logical outline that assistive tech relies on
  • It is a syntax error

Answer: It breaks the logical outline that assistive tech relies on. Skipping levels confuses the document outline that screen reader users navigate by; go in order H2, then H3.

Which link text is the most accessible?

  • this
  • Read the installation guide
  • link
  • click here

Answer: Read the installation guide. Descriptive link text makes sense out of context, which helps users who navigate by jumping between links.

What should an image's alt text describe?

  • The file size
  • The camera model
  • The file format
  • The image's meaning or content for someone who cannot see it

Answer: The image's meaning or content for someone who cannot see it. Alt text conveys the image's purpose or content so screen reader users get the same information.

When is empty alt text (alt="") appropriate for an image?

  • For purely decorative images that add no information
  • For every image
  • Never
  • Only for logos

Answer: For purely decorative images that add no information. Decorative images that carry no meaning take empty alt text so screen readers skip them rather than reading noise.

What makes a Markdown table more accessible?

  • Coloured cells
  • Having a clear header row so cells are associated with headers
  • Removing the separator row
  • Using only one column

Answer: Having a clear header row so cells are associated with headers. A proper header row lets assistive tech announce each data cell with its column heading.

Why shouldn't you rely on bold or colour alone to convey meaning?

  • It increases file size
  • It is slower to type
  • Bold is not valid Markdown
  • Users who can't perceive the styling miss the meaning

Answer: Users who can't perceive the styling miss the meaning. Meaning carried only by formatting is lost to people who can't see the emphasis; state it in words too.

What is the accessibility benefit of a logical heading hierarchy?

  • It changes the page language
  • It hides headings from search engines
  • It lets users jump through the document structure with a screen reader
  • It compiles faster

Answer: It lets users jump through the document structure with a screen reader. A correct hierarchy creates a navigable outline, so users can move by heading level to find sections quickly.

Which is the better approach for a meaningful image in documentation?

  • Omit the alt attribute entirely
  • Write concise alt text that conveys its purpose
  • Use the filename as alt text
  • Set alt to the word image

Answer: Write concise alt text that conveys its purpose. Concise, purposeful alt text communicates what the image shows; filenames and generic words are not helpful.

Good Markdown structure for screen readers means primarily what?

  • Real headings, lists, and link text rather than visual tricks
  • Avoiding all headings
  • Writing everything in one paragraph
  • Using as many emojis as possible

Answer: Real headings, lists, and link text rather than visual tricks. Semantic structure, true headings, real lists, and descriptive links, gives assistive tech something meaningful to convey.

Continue this course