Scopes
Learn about Vale's advanced markup-specific scoping system.
Vale is “markup aware,” which means that it’s capable of both applying rules to and ignoring certain sections of text. This functionality is implemented through a scoping system.
A scope is specified through a selector such as paragraph.rst, which indicates that the rule applies to all paragraphs in reStructuredText files.
Here are a few examples:
commentmatches all source code comments;comment.linematches all source code line comments;heading.mdmatches all Markdown headings; andtext.htmlmatches all HTML scopes.
Vale classifies files into one of three types—markup, code, or text—that determines what scopes are available.
Within each type, there can be multiple supported formats—such as Markdown and AsciiDoc under markup. Since each format has access to the same scopes, rules are compatible across all formats within a particular type.
Markup
The default behavior for markup files is to apply rules to all non-ignored sections of the file. This means that for most rules you don’t need to specify a scope.
For rules that need to target specific sections of the file, you can use the following scopes:
heading
Matches all h{1,...} tags. You can specify an exact level by
appending tags—for example, heading.h1 matches all h1 tags.
table.header
Matches all th tags.
table.cell
Matches all td tags.
table.caption
Matches all caption tags.
figure.caption
Matches all figcaption tags.
list
Matches all li tags.
paragraph
Matches all body paragraphs (segments of text separated by two newlines). Headings, list items, table cells, and blockquotes are not paragraphs.
sentence
Matches all sentences.
blockquote
Matches all blockquote tags.
alt
Matches all alt attributes.
summary
Matches all body text (excluding headings, code spans, code blocks, and table cells). This scope is useful for rules that need to match only sentence-level text content (such as readability scores).
raw
Uses the raw, unprocessed markup source instead of a specific scope. This scope is useful for regex-based rules that need to match against the original source text.
Inline scopes
Requires Vale v3.17.0 or later.
Inline elements have their own scopes, which let a rule target the text inside a link, a code span, or an emphasized phrase:
link
Matches the text of all a tags.
code
Matches all code and tt tags (code spans).
strong
Matches all strong and b tags.
emphasis
Matches all em and i tags.
These are siblings of text, not children of it: the scope is link, not text.link.
Scopes are matched by containment, so a rule scoped to text would also match text.link—meaning every ordinary rule would run a second time over each link.
A rule that asks for one of these scopes is the only kind that runs against it:
Scoping to code is worth noting: the text inside code spans is skipped by default (IgnoredScopes defaults to tt, code, and kbd), so a rule has to ask for it explicitly. To exclude inline text rather than target it, see IgnoredScopes.
Class scopes
Requires Vale v3.17.0 or later.
Markup that carries no distinct tag of its own can still be selected by the classes wrapping it. Any enclosing class is appended to the scope as .class.<name>.
An AsciiDoc block title, for example, renders as <div class="title">—indistinguishable from body text by tag alone:
A directive's name lands here too: a MyST or Quarto :::{note} scopes its content as class.note, and a QDoc \note does the same.
Classes nest, so a block inside two classed elements is reachable as text.class.outer.class.inner—and every block inside a classed container carries its class, however many blocks that is. To ignore classed content rather than target it, see IgnoredClasses.
The supported formats for markup files are:
HTML Built-in
Markdown Built-in, including R Markdown
MDX Built-in
MyST Built-in
Org Built-in
QDoc Built-in
Quarto Built-in
The formats marked as Built-in are included with Vale by default. The other formats require a third-party dependency to be installed. See each format’s documentation for more information and installation instructions.
Code
There are two code scopes: comment.line and comment.block.
See the Code documentation for more information.
Selectors
How a selector matches
Every section of text Vale finds carries a scope built from dot-separated parts. A list item in a Markdown file, for example, is text.list.md.
A selector matches when all of its parts appear in that scope. It isn't a prefix match or an exact match, and the order you write the parts in doesn't matter:
Selector
Matches text.list.md?
list
Yes
list.md
Yes
md.list
Yes—order is irrelevant
text.list
Yes
list.text.md
Yes
heading
No—not one of its parts
This is why you can qualify any selector with a file extension to make it format-specific. paragraph matches paragraphs everywhere; paragraph.rst matches them only in reStructuredText.
It's also why a selector with fewer parts is broader: text matches nearly everything, because nearly every scope contains it.
Combining selectors
Rules may define multiple scopes by using a YAML array. An entry matches if any of them does:
Any scope prefaced with ~ is negated:
You can chain multiple scopes together using &, which requires all of them:
Chains that name paragraph, sentence, or an inline scope require Vale v3.18.0 or later. Earlier versions silently matched nothing for those chains.
The two combine: & is an AND within a single entry, and the array is an OR across entries.
Because matching is by parts rather than by prefix, a narrower-looking scope isn't always narrower. text.list and list select the same blocks—the extra text adds nothing, since every list item's scope already contains it.
Last updated
