rumdl 0.3.0

A fast Markdown linter and formatter written in Rust
Documentation
# MD024 - Avoid duplicate heading text

Aliases: `no-duplicate-heading`

## What this rule does

Checks that headings don't have identical text, preventing confusion and navigation issues.

## Why this matters

- **Better navigation**: Unique headings make it easier to find specific sections
- **Clear table of contents**: Automated TOCs need unique headings to create proper links
- **Improved accessibility**: Screen readers rely on unique headings for navigation
- **Avoid confusion**: Readers won't wonder which "Introduction" section they're in

## Examples

<!-- rumdl-disable MD024 -->

### ✅ Correct

```markdown
# Project Setup

## Installing Dependencies

Details about npm install...

## Configuring the Environment

Details about environment setup...

## Running Tests

How to run the test suite...
```

### ❌ Incorrect

```markdown
# Project Setup

## Setup

Details about npm install...

## Setup

Details about environment setup...

## Setup

How to run the test suite...
```

### 🔧 Fixed

```markdown
# Project Setup

## Installing Dependencies

Details about npm install...

## Environment Configuration

Details about environment setup...

## Test Setup

How to run the test suite...
```

<!-- rumdl-enable MD024 -->

## Configuration

```toml
[MD024]
allow-different-nesting = false        # Allow duplicates at different levels (default: false)
siblings-only = true                   # Only check siblings at same level (default: true)
allow-different-link-anchors = true    # Treat headings with different {#custom-id} as distinct (default: true)
```

**Note:** rumdl defaults `siblings-only` to `true` (unlike markdownlint's `false` ) to reduce false positives in CHANGELOGs and structured documentation. To match markdownlint's stricter behavior, set
`siblings-only = false` .

### `allow-different-link-anchors`

When `true` (the default), two headings with the same visible text are considered distinct if they carry different `{#id}` suffixes — a syntax supported by Hugo, Pandoc, Kramdown, and other processors. For example:

```markdown
#### Unit testing

#### Unit testing {#custom-anchor}
```

These produce different rendered anchors and are not flagged. This matches the effective behavior of markdownlint, which compares raw heading text (which retains the `{#id}` suffix).

Set to `false` to ignore `{#id}` suffixes during deduplication (the previous behavior).

## Headings inside blockquotes

Headings inside blockquotes (including nested quotes, a quote inside a list item
and a list item inside a quote) are checked like any other heading. They share the
duplicate set with unquoted headings, because every heading gets an anchor, and
they follow `allow-different-nesting` and `siblings-only` exactly as a heading
inside a list item does: a quoted heading takes its place in the section path.

```markdown
# Setup

> # Setup
```

## Automatic fixes

This rule cannot be automatically fixed because changing heading text requires understanding the content's meaning. You'll need to manually update duplicate headings to be more descriptive.

## Learn more

- [Writing better headings](https://www.nngroup.com/articles/headings-pickup-lines/)
- [Accessible heading structure](https://www.w3.org/WAI/tutorials/page-structure/headings/)

## Related rules

- [MD001](md001.md): Use consistent heading levels
- [MD025](md025.md): Use only one top-level heading
- [MD026](md026.md): Remove trailing punctuation in headings
- [MD043](md043.md): Require specific heading structure