Skip to content

Add MenuArrows rule to flag incorrect menu navigation separators#137

Merged
theletterf merged 6 commits into
mainfrom
add-menu-arrows-rule
Apr 29, 2026
Merged

Add MenuArrows rule to flag incorrect menu navigation separators#137
theletterf merged 6 commits into
mainfrom
add-menu-arrows-rule

Conversation

@florent-leborgne
Copy link
Copy Markdown
Member

Summary

Adds a new MenuArrows rule that flags incorrect menu navigation separators and suggests the correct character, as specified in the Writing about the UI style guide (Menus component row: "Use arrows (→) to tell the user where to find the command").

What the rule catches

Two tokens cover the two wrong patterns writers use:

Token 1: =>
Catches => used as a menu separator in all cases. This is an unambiguous pattern — => in prose documentation almost exclusively appears as a misused menu separator, and Vale already excludes code blocks and inline code spans automatically.

Token 2: [A-Za-z]{3,}\s>\s[A-Za-z]{3,}
Catches > used as a menu separator. The pattern requires at least 3 letters immediately on both sides of >. The design decisions:

  • Requires 3+ letters on each side — excludes single-variable comparisons like x > y or ab > cd, which are the main source of false positives for a bare > pattern. Real UI menu labels are always full words (e.g. File, New, Management).
  • Does not require letters only — the {3,} quantifier stops at the first non-letter, so count > 10 is skipped because 10 contains no letters, and x > 0 is skipped for the same reason.
  • Inline code is excluded automatically — Vale strips inline code spans (`...`) before running existence rules, so `a > b` in code is never flagged.
  • Works with bold markup — Vale strips ** before matching, so **File** > **New** is seen as File > New and correctly caught.

Known limitation

Vale deduplicates matches within the same paragraph when two consecutive lines share the same leading bold term. For example, if a paragraph contains both **Settings** > **Advanced** and **Settings** > **Basic** without a blank line between them, only the first line is flagged. This is a Vale internals behaviour that cannot be worked around at the regex level.

Made with Cursor

Flags the use of > or => as menu separators instead of the correct → character, as defined in the style guide (https://www.elastic.co/docs/contribute-docs/style-guide/ui-writing).

Made-with: Cursor
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 28, 2026

Vale Linting Results

Summary: 10 warnings, 10 suggestions found

⚠️ Warnings (10)
File Line Rule Message
.github/test-fixtures/sample-violations.md 7 Elastic.Articles Use 'an FAQ' instead of 'a FAQ'. The article depends on pronunciation, not spelling.
.github/test-fixtures/sample-violations.md 7 Elastic.Articles Use 'an HTML' instead of 'a HTML'. The article depends on pronunciation, not spelling.
.github/test-fixtures/sample-violations.md 7 Elastic.Articles Use 'an SQL' instead of 'a SQL'. The article depends on pronunciation, not spelling.
.github/test-fixtures/sample-violations.md 11 Elastic.BritishSpellings Use American English spelling 'optimize' instead of British English 'optimise'.
.github/test-fixtures/sample-violations.md 11 Elastic.BritishSpellings Use American English spelling 'customize' instead of British English 'customise'.
.github/test-fixtures/sample-violations.md 11 Elastic.BritishSpellings Use American English spelling 'behavior' instead of British English 'behaviour'.
.github/test-fixtures/sample-violations.md 27 Elastic.DontUse Don't use 'just'.
.github/test-fixtures/sample-violations.md 27 Elastic.DontUse Don't use 'please'.
.github/test-fixtures/sample-violations.md 27 Elastic.DontUse Don't use 'aka'.
.github/test-fixtures/sample-violations.md 35 Elastic.Articles Use 'an HTML' instead of 'a HTML'. The article depends on pronunciation, not spelling.
💡 Suggestions (10)
File Line Rule Message
.github/test-fixtures/sample-violations.md 15 Elastic.WordChoice Consider using 'efficiently' instead of 'Simply', unless the term is in the UI.
.github/test-fixtures/sample-violations.md 15 Elastic.WordChoice Consider using 'allowlist' instead of 'whitelist', unless the term is in the UI.
.github/test-fixtures/sample-violations.md 15 Elastic.WordChoice Consider using 'blocklist' instead of 'blacklist', unless the term is in the UI.
.github/test-fixtures/sample-violations.md 15 Elastic.WordChoice Consider using 'efficient' instead of 'easy', unless the term is in the UI.
.github/test-fixtures/sample-violations.md 19 Elastic.OxfordComma Use the Oxford comma in 'reading, writing and executing.'.
.github/test-fixtures/sample-violations.md 23 Elastic.Wordiness Consider using 'to' instead of 'In order to'.
.github/test-fixtures/sample-violations.md 23 Elastic.Wordiness Consider using 'because' instead of 'due to the fact that'.
.github/test-fixtures/sample-violations.md 23 Elastic.Wordiness Consider using 'many' instead of 'a large number of'.
.github/test-fixtures/sample-violations.md 31 Elastic.Exclamation Use exclamation points sparingly. Consider removing the exclamation point.
.github/test-fixtures/sample-violations.md 31 Elastic.Exclamation Use exclamation points sparingly. Consider removing the exclamation point.

The Vale linter checks documentation changes against the Elastic Docs style guide.

To use Vale locally or report issues, refer to Elastic style guide for Vale.

This comment was marked as low quality.

Copy link
Copy Markdown
Member

@theletterf theletterf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

I would suggest going for a substitution extension point, so that editors can do quick replacements of what is a hard to type character like the arrow:

extends: substitution
message: "Use '%s' to separate menu items, not '%s'. Example: Select Manage index → Add lifecycle policy."
link: 'https://www.elastic.co/docs/contribute-docs/style-guide/ui-writing'
level: suggestion
nonword: true
action:
  name: replace
swap:
  "(=>)": "→"
  '[A-Za-z]{3,}\s(>)\s[A-Za-z]{3,}': "→"

WDYT?

@florent-leborgne
Copy link
Copy Markdown
Member Author

Thanks @theletterf — you were right. Vale does support backreferences in substitution replacements. Switched to substitution with $1 → $2 for the > pattern, which correctly replaces only the separator while keeping the surrounding label words in place. For => it's a direct swap (=>). The rule now offers one-click fixes for both cases. Also downgraded to suggestion level as you proposed.

@florent-leborgne
Copy link
Copy Markdown
Member Author

Reverting the substitution approach after further testing. The fix works correctly for plain text (Vale produces a precise column span), but for bold markup like **File** > **New**, Vale maps the span to the entire line — meaning the auto-fix would replace Go to **File** > **New** to create. with just File → New, stripping the surrounding sentence and bold markers. Too risky to offer as a one-click fix. Back to existence with a warning level so writers see the issue and fix it manually.

Add quick-fix actions for menu separator warnings and a raw-scope companion rule for bold UI paths while keeping local Vale config aligned with CI.

Made-with: GPT-5.5
Made-with: Cursor
@theletterf
Copy link
Copy Markdown
Member

Thanks Florent. I pushed an update that keeps the main rule as existence, but adds an edit action so Vale/LSP can offer a quick fix from > or => to .

I also added a companion MenuArrowsBold rule using scope: raw for bold UI paths. That lets us catch common docs patterns like **File** > **New**, **UI** > **Settings**, and **Fill color > As number** even though the CI config ignores strong and b scopes globally.

Local testing with vale --config .vale.ini --no-global now confirms:

  • Plain menu paths and => in prose are flagged.
  • Bold menu paths are flagged.
  • Inline code examples like `a > b` and `a => b` are skipped.
  • Fenced-code and indented-code samples are skipped.
  • The JSON output includes the edit action metadata for quick fixes.

The rule can still flag prose comparisons such as request rate > response rate, but that seems acceptable since prose should use "greater than" rather than >.

Resolve the Vale config conflict by keeping the branch's CI-aligned scope ignores while preserving main's vocabulary and spelling settings.

Made-with: GPT-5.5
Made-with: Cursor
@theletterf theletterf merged commit 26e5c99 into main Apr 29, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants