netajam3k downloadsEasily adjust header levels in Markdown documents by increasing or decreasing their levels.
The Heading Adjuster Plugin for Obsidian allows users to easily adjust the levels of headings in their Markdown documents. Users can increase or decrease heading levels by a specified number of levels, across the entire document, a selection, a specified range of lines, a range pinned to the cursor, or just the line the cursor is on. The plugin also provides convenient default settings for heading adjustments.
From inside Obsidian: open Settings → Community plugins, browse for "Heading Adjuster", and install it.
Manually:
main.js, manifest.json, and styles.css from the
latest release..obsidian/plugins/header-adjuster directory
— the folder name has to match the plugin id in manifest.json, which is
still header-adjuster from before the plugin was renamed.The plugin provides the following commands accessible from the command palette. The two "by N" commands name your current default, so N is whatever the settings say.
#,
whatever sits above it.Each of those four is its own command, so you never have to choose one direction over another in the settings — bind the ones you use and leave the toggle for whichever you want on a single key.
Clicking the ribbon icon opens a menu with options to:
Obsidian's mobile toolbar shows commands as icons with no names, so every command this plugin registers carries its own symbol and no two are alike:
| Symbol family | Scope |
|---|---|
| Solid arrow | the dialog — you say how far |
| Page with +/− | the whole note |
| Box with +/− | the selection |
| Ringed chevron | your custom range |
| Bare chevron | the current line |
| A struck through | remove the heading |
| Large H1 | top-level heading |
| Arrow turning out | parent of the heading above |
| Equals sign | sibling of the heading above |
| Arrow turning in | child of the heading above |
Up increases and down decreases throughout, so there are two things to learn rather than sixteen. The two turning arrows are mirrors of one another, for the same reason: parent and child are one step in opposite directions.
If you only have one slot, spend it on the hash: "Toggle heading on current line" both makes a section and unmakes it.
To add one: Settings → Toolbar, then pick the commands you want. The ribbon menu shows the same symbols beside their names, which is the quickest way to learn which is which.
When using the "Increase heading level..." or "Decrease heading level..." commands, a dialog will prompt you to:
The current-line commands are the finest of the three scopes, and the only ones
that treat a line with no # as a heading of level zero. That makes them a way
to write a heading as well as to move one:
| Before (cursor on the line) | Command | After |
|---|---|---|
Some prose |
Increase | # Some prose |
# Some prose |
Increase | ## Some prose |
## Some prose |
Decrease | # Some prose |
# Some prose |
Decrease | Some prose |
So a plain line becomes a heading by increasing it once, and again for each level
deeper you want. Decreasing an # takes the heading back off.
Unlike the document and selection commands, these leave nesting alone: only the line you are on moves, and headings nested under it stay where they are. If you want a heading and everything beneath it to move together, select those lines and use the selection commands. Conversions do not apply either — a line is not a section, so there is no body to indent into a bullet. A line inside a code fence is left as the code it is.
The placement commands say what the line should be rather than how far to move it, so they land in one step and ignore your default shift. Three of them read the nearest heading above the current line:
# Guide
## Setup
### Prerequisites
some prose ← cursor here; the heading above is `### Prerequisites`
| Command | Result |
|---|---|
| Make current line a parent of the heading above | ## some prose |
| Make current line a sibling of the heading above | ### some prose |
| Make current line a child of the heading above | #### some prose |
| Make current line a top-level heading | # some prose |
| Remove heading from current line | some prose |
They work on a line that is already a heading too, which is how you re-level one
without counting: put the cursor on it and make it a child of the heading above.
Because none of them reads the level the line is written at, the same command
lands in the same place whether the line was plain text, an # or an ###### —
so it is one repeatable step rather than a count-and-adjust.
Parent is the one that changes the outline around it. Where sibling and child join the section above, a parent encloses it:
# Guide # Guide
## Setup → ## Setup
### Notes ## some prose ← `### Notes` is now inside this
some prose
That is how you open a section above work you have already written, which is the direction an outline is read in but rarely the one it gets typed in.
If there is no heading above the line, "parent", "sibling" and "child" all
produce an # — the note itself is what encloses the line. A parent of an #
is an # too, since nothing in an outline sits above the top of it. A heading
inside a code fence does not count as the heading above, and a line inside one is
left alone.
"Toggle heading on current line" is the sibling placement and the removal in one command, which is what you want if you have a single hotkey or a single free slot on the mobile toolbar to spend:
# Guide
## Setup
some prose ← cursor here
| Toggle set to | Once | Twice |
|---|---|---|
| Same level as the heading above | ## some prose |
some prose |
| One level below the heading above | ### some prose |
some prose |
| One level above the heading above | # some prose |
some prose |
| Top level | # some prose |
some prose |
Which of the four it uses is yours to set, under Toggle puts the heading at in the settings. It ships as "same level as the heading above". This only decides where the one toggle aims: all four have commands of their own, so setting it never puts a level out of reach.
A heading already at some other level is moved to the one you chose rather than removed, so the second press is what takes it off. That keeps two presses enough to reach plain text from anywhere, and keeps a press from ever destroying a level you would have to retype. It also means the toggle only takes off the level it puts on: set to "one below", it will move a sibling heading rather than remove it.
A line cannot be a bullet and a heading at once, so writing a heading onto a list item replaces its marker instead of sitting in front of it — indentation included, since a heading only counts at the start of a line:
| Before | After (increase, or a placement) |
|---|---|
- Some prose |
# Some prose |
* Some prose |
# Some prose |
1. Some prose |
# 1. Some prose |
Ordered items are left alone: 1. is not a bullet, and the plugin keeps one
definition of a list item across every command. Removing a heading never writes
a bullet back, either — Markdown records no provenance for the marker it
replaced, so there is nothing to restore.
A list item holds whatever is indented past it; a heading holds whatever follows it until the next heading. They disagree about what sits underneath, so a line that stops being one and starts being the other leaves its content answering to nothing.
Turning a list item into a heading — with "Toggle heading" or any of the four placement commands — brings the items nested under it along, by as much as the item itself lost:
- A - A
- B - B
- C - C
- D ← caret # D
- E - E
- etc - etc
Left where they were, those children sit at an indent nothing encloses any more — which CommonMark reads as a code block rather than a list. Bring nested list items along is on by default for that reason; switch it off to write only the line the caret is on.
The block ends at the first line indented no further than the item itself, so a sibling further down and everything under it stay put. A blank line does not end it. A line that is not a list item has nothing nested to carry, so a paragraph turned into a heading is written on its own.
Removing a heading goes the other way, and ships doing what it always did: writing the text on its own. Removing a heading leaves can instead put the line back in a list, either on its own or carrying the section the heading held:
| Setting | # D followed by - E becomes |
|---|---|
| Plain text (default) | D / - E |
| A list item | - D / - E |
| A list item, with the section nested under it | - D / - E |
The section ends where the heading's does — at the next heading, whatever its level. It moves as one block, so its own nesting is untouched, and it moves by one level in whatever the section already indents by: a tab-nested list gets a tab, a four-space one gets four spaces. A section with no nesting to go on takes the width of the marker instead.
The round trip does not close on depth: a heading remembers nothing about how far the item it came from was indented, so an item lifted out of four levels of nesting comes back at the top level. Markdown records no provenance for that, which is the same limit ADR-0001 describes.
The five other scopes each name their range in their own command name, which is what makes them safe to bind: the hotkey does what the palette said it would. The custom range is the one whose boundaries you choose, and it is there for the range you want that the plugin does not ship — most often everything after the cursor, when a note has been pasted into the middle of another and needs pushing a level deeper.
Two settings pick its boundaries — a top and a bottom, each naming the place it sits on:
| Top | Bottom | The range |
|---|---|---|
| Top of the note | End of the note | the whole note (default) |
| Cursor line | End of the note | the cursor line to the end |
| Top of the note | Cursor line | the top of the note to the cursor |
| Cursor line | Cursor line | the cursor line alone |
The top offers only the start of the note or the cursor, and the bottom only the cursor or the end, so there is no way to set a range that runs backwards.
The cursor's own line is always inside the range. Standing on ## Section with
the top set to the cursor line and shifting down moves that heading too, along
with everything under it.
Both boundaries default to the note's own edges, so before you touch them the custom commands are a second copy of the document commands rather than a surprise. A boundary changed mid-session takes effect immediately — there is no reload.
Line numbers are deliberately not offered here. A range baked into a hotkey outlives the note it was set for; for a one-off range, use Increase heading level... and type it.
Access the plugin settings from the Obsidian Settings under the "Heading Adjuster" section. They are grouped by the commands they govern — Default shift, Custom range, Toggle heading on current line, and Bullet conversion:
#), one level
above the heading above, the same level as it, or one below it. Defaults to
the same level. Each of the four is also a command in its own right, so this
only decides where the one toggle aims.To increase all headings in a document by 2 levels:
Ctrl+P or Cmd+P).2 in the modal and click "Submit".To decrease headings from line 5 to line 20 by 1 level:
Ctrl+P or Cmd+P).1 in the modal.5 for the start line.20 for the end line.To increase every heading in the note using the default setting:
Ctrl+P or Cmd+P).To do the same to a selection, select the lines first and run "Increase heading level in selection by N".
To turn the paragraph you are looking at into an ### heading:
To take it back off, run "Remove heading from current line" once, or "Decrease
heading level of current line by N" until the # characters are gone.
To turn a line into a subheading of whatever section it already sits in:
The level is worked out from the note, so this does the right thing whether the
section above is an # or an #####.
See CONTRIBUTING.md for setup, the checks a change has to
pass, and where each kind of code belongs. docs/architecture.md describes the
layering, and CONTEXT.md defines the vocabulary the code is written in.
This plugin is licensed under the MIT License.