TL;DR
Markdown doesn't have a real indent feature. The only place it natively respects whitespace is inside lists — two spaces for nested unordered, three for ordered. For paragraph indents, use or a blockquote. For code inside a list item, indent four spaces past the bullet. Four spaces outside a list creates a code block by accident, which is the single most common gotcha.
The honest answer to "how do I indent in markdown" is that you usually can't. Markdown collapses leading whitespace at the start of a paragraph, treats four spaces as a code block, and only respects indentation inside list items. Everything else is a workaround using HTML entities, blockquotes, or raw HTML.
This guide covers every method that actually works, ranks them by platform support, and shows the five failure modes you'll hit in real docs.
Prefer video? NeuralNine's beginner crash course covers lists and indentation along with the rest of markdown:
The short answer: markdown doesn't really indent#
Markdown was designed in 2004 to be a plain-text format that converts cleanly to HTML. HTML doesn't care about leading whitespace in source — it collapses it. Markdown inherited that behavior.
So when you type four tabs at the start of a paragraph and the rendered output looks identical to the unindented version, the parser is working as designed. The exception is inside lists, where indentation determines nesting depth and is part of the syntax itself.
That means "indent in markdown" really means one of four things:
- Nest a list (use indentation as syntax)
- Push text right visually (use
or HTML) - Quote a block (use
>as a left-rail indent) - Indent code inside a list (use four spaces past the bullet)
Each has its own rules and its own breakage modes. Let's go through them.
Indent a nested list (the only indent markdown natively supports)#
Nested lists are the one case where markdown is unambiguous: the indent of the child item must align with the text of the parent, not the bullet.
For unordered lists, that's two spaces. For ordered lists, three (because 1. is three characters wide).
Start with a parent bullet
Write your top-level item with a single - or * :
- Parent itemIndent the child by two spaces
The child bullet's - lines up with the parent's text, which is two spaces in:
- Parent item
- Child itemGo deeper by adding two more spaces per level
Each level adds another two spaces:
- Level 1
- Level 2
- Level 3
- Level 4Mix ordered and unordered
Ordered items use three spaces of indent for their children because 1. is wider:
1. First step
- Sub-bullet under step 1
- Another sub-bullet
2. Second stepThe CommonMark spec on list items is the canonical source here, and GitHub Flavored Markdown spec follows it almost exactly.
Two spaces, not four
You'll see old tutorials say to use four spaces for nested lists. That works on most renderers, but four spaces is also the trigger for an indented code block. If you ever paste a list snippet outside its parent context, four-space children will render as code. Two spaces is safer.
What about tab characters?#
CommonMark treats a tab as equivalent to four spaces, but tabs are a trap. Most editors auto-convert tabs to spaces on save. Git diff settings, CI formatters, and copy-paste between apps all mangle tabs silently. Pick spaces and commit to them.
Indent a paragraph or block of text#
Markdown has no first-line indent and no left-margin indent for paragraphs. You have three real options, ranked by reliability.
Option 1: blockquote as a left-rail indent#
A > at the start of a line creates a blockquote, which most renderers style with a left margin and a vertical bar:
Regular paragraph here.
> This paragraph is visually indented because it's a blockquote.
> Subsequent lines continue the same block.It's not technically an indent — it's a quote. But it renders as indented text everywhere, including in plain-text terminals. If you want a deeper dive on the syntax, see the blockquote syntax guide.
Option 2: non-breaking space entities#
The HTML entity (and friends like   for a wider em-space) push text right without triggering whitespace collapse:
This paragraph starts with four non-breaking spaces, simulating a first-line indent.This works because markdown parsers pass HTML entities through to the output untouched. The browser then renders each as a real space. MDN has the full reference on the non-breaking space entity and other character codes.
Notion and some hosted CMS pipelines strip HTML entities during import. Test before you commit a long doc to entity-based indents.
Option 3: raw HTML with inline CSS#
For MDX and most markdown flavors that allow raw HTML, you can use:
<p style="text-indent: 2em;">This paragraph has a real first-line indent via CSS.</p>This is the cleanest semantically, but it's also the most likely to be stripped by sanitizers. GitHub allows it in READMEs. GitLab allows it. Notion does not. Reddit does not.
Indent code inside a list item#
This is the case that breaks the most docs. You want a code block that belongs to a list item, like step 3 in a tutorial. The rule: indent the code fence (or the indented code) to align with the parent item's text — typically four spaces in.
1. Install the package.
2. Add the import.
```ts
import { Dokly } from "dokly";- Initialize the client.
Note the four-space indent before the triple backticks. Without it, the code block escapes the list and breaks the numbering. Step 3 will render as "1." instead of "3." because the parser thinks the list ended.
<Callout type="warning" title="GitHub and Mintlify render this differently">
GitHub is strict about the four-space rule. Mintlify and some MDX renderers are forgiving and accept two spaces or even none — but if you ever move that content to GitHub, the numbering breaks. Always use four spaces past the bullet for code blocks inside lists.
</Callout>
For inline code inside a list item, no indent rule applies — just write your backticks normally:
```markdown
1. Run `npm install`.
2. Then run `npm run build`.Indent across platforms: what renders where#
Not every indent trick survives every renderer. Here's the truth table for the most common platforms, based on testing each method against current versions as of April 2026.
| Method | GitHub | GitLab | MDX / Dokly | Notion | Obsidian | |
|---|---|---|---|---|---|---|
| Nested list (2-space) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Blockquote > | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
entities | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
Raw HTML <p style> | ✅ | ✅ | ✅ | ❌ | ⚠️ | ❌ |
| 4-space code in list | ✅ | ✅ | ✅ | ⚠️ | ✅ | ✅ |
| Tab character indent | ⚠️ | ⚠️ | ⚠️ | ❌ | ⚠️ | ❌ |
✅ = renders as expected · ⚠️ = works inconsistently · ❌ = stripped or broken
The two methods that work everywhere are nested lists and blockquotes. If you're writing a README that needs to render on GitHub, GitLab, npm, and crates.io simultaneously, stick to those. The same applies when you're writing READMEs that render everywhere.
Common indent breakages and how to fix them#
Five real failures you'll hit, in order of frequency.
1. Tabs converted to spaces (or vice versa)#
You wrote a nested list with tabs. Your editor saved spaces. Or you wrote spaces, your linter changed them to tabs, and CI flipped them again. The list flattens in the rendered output.
Fix: add .editorconfig to your repo with indent_style = space and indent_size = 2. Most editors respect it automatically.
2. Nested list flattening on paste#
You copied a list from Notion or Google Docs into a markdown file. The indentation looked right but used non-breaking spaces or different whitespace. The parser saw one flat list.
Fix: paste into a plain-text editor first, then re-indent manually with regular spaces.
3. Accidental code block from 4-space indent#
You wanted an indented paragraph. You used four spaces. Markdown turned it into a code block with a monospace font and a gray background.
Fix: use a blockquote (>) or entities instead. Or use three spaces if you only want a small visual indent and don't care about precise alignment.
4. MDX JSX parse errors from indented <#
In MDX, leading whitespace before a < character can confuse the parser, especially if the < is followed by a letter. The build fails with a cryptic syntax error.
Fix: keep JSX components flush-left. Don't indent <Callout> or <Card> opening tags inside lists. If you need them inside list items, use a fragment or restructure with the component on its own line.
- A list item with a callout inside:
<Callout type="tip">This works because the callout is flush-left.</Callout>
- Next itemThe MDX content syntax docs explain exactly how the parser interleaves markdown and JSX.
5. Table cell content won't indent#
Markdown table cells don't respect leading whitespace at all. You can't indent the contents of a cell with spaces.
Fix: use entities, or accept that table cells are single-line and put the indented content outside the table. Same advice applies to horizontal rule whitespace gotchas — markdown's whitespace rules are unforgiving for any block element that isn't a list.
When to stop indenting and use a real component#
Most of the time someone reaches for indent tricks, what they actually want is a different visual element: a callout box, a numbered step, a card, a code panel. Indent is a low-bandwidth proxy for structure.
If you're writing in MDX, use the right component:
- For a "note" or "warning" indent → use a Callout
- For a step-by-step list with code → use Steps
- For a grid of options → use Cards
- For a side panel of related info → use a Tab or Accordion
Compare these two ways to write the same content. With raw markdown indent tricks:
**Tip:**
Use Cmd+K to jump to any page instantly.
This works on every page in your docs.With a real component:
<Callout type="tip">
Use **Cmd+K** to jump to any page instantly. This works on every page in your docs.
</Callout>The component version renders consistently, survives platform migrations, and doesn't break if someone re-indents the file. See Dokly's MDX components reference for the full list.
This is why switching to a visual MDX editor eliminates most indent headaches — you don't write whitespace at all. You drop in a Callout, type your text, and the rendered output is identical across every device and viewport.
Frequently Asked Questions#
Why doesn't markdown indent when I press tab?#
Markdown collapses leading whitespace at the start of a paragraph. A tab or a few spaces at the start of a line either does nothing, gets stripped, or — if you use exactly four spaces — turns the line into a code block. The only place markdown natively respects indentation is inside lists. For everything else you need a blockquote, an HTML entity like , or a raw HTML tag.
How many spaces should I use to indent a nested list?#
Use two spaces for unordered lists and three spaces for ordered lists, measured from the start of the parent item's text — not from the bullet. CommonMark and GitHub Flavored Markdown both follow this rule. Four spaces also works on most renderers, but it can accidentally trigger a code block if you're not inside a list, so two is the safer default.
How do I indent the first line of a paragraph in markdown?#
Markdown has no native first-line indent. The two workarounds are inserting non-breaking spaces ( ) at the start of the paragraph, or wrapping the paragraph in a raw HTML element with inline CSS like <p style="text-indent: 2em;">. The HTML approach works on GitHub, GitLab, and MDX renderers but is stripped by most CMS pipelines and by Notion.
Why does my indented text turn into a code block?#
If you indent a line by four or more spaces and it's not inside a list, the markdown parser treats it as an indented code block. This is part of the CommonMark spec. To prevent it, either use fewer spaces, wrap the line in a blockquote with >, or use HTML entities ( ) which the parser doesn't count as leading whitespace.
Can I use tab characters to indent in markdown?#
Technically yes, but it's unreliable. CommonMark treats a tab as equivalent to four spaces, but editors, git diff settings, and CI pipelines often convert tabs to two spaces (or vice versa) without warning. Use explicit spaces — two for nested lists, HTML entities for paragraph indents — so what you write is what renders.
How does MDX handle indented content differently?#
MDX parses your file as both markdown and JSX, which means leading whitespace before a < character can confuse the parser. Indenting a line that starts with a JSX tag often produces a build error. Keep JSX components flush-left, and only indent content inside them when you're sure the renderer accepts it. In Dokly's visual MDX editor, indentation is handled by components like Steps and Callout, so you don't write whitespace at all.
Next steps#
Blockquote syntax guide
The other indent-adjacent markdown feature
MDX components reference
When to stop indenting and use a real component
Visual MDX editor
Skip the whitespace problems entirely
README generator guide
Markdown that renders everywhere
If you're tired of fighting markdown whitespace and want a docs editor where Callouts, Steps, and Cards just work without indent gymnastics, try Dokly free. The visual MDX editor handles the rendering so you can focus on what the doc actually says.