Skip to content

Show the Markdown shortcut on each Slash menu row that has one #346

Description

@HMarzban

Parent

#328. Related: #251

What to build

People who insert headings from the Slash menu are not told that typing ## does the same. Each row that has a Markdown shortcut should show it as a hint: quiet text at the row's end.

A hint must be true where it shows. Some Markdown shortcuts fail in some blocks: ## in a list item stays text, and - on a heading line stays text. Every Markdown shortcut works on a top-level paragraph. So a hint shows only there, and only on desktop until a phone check passes.

Acceptance criteria

  • On a top-level empty paragraph, rows show these hints:
    • Heading 1–6: # to ######
    • Bullet List -, Ordered List 1., Task List []
    • Blockquote >, Code Block ```
  • Subtitle, Normal, the media row (id picture) and Link to a section show no hint.
  • In a heading line, a list item, a task item or a blockquote, no row shows a hint. The rows themselves stay.
  • On the phone, no hint shows.
  • Screen readers do not read the hint. Each option's accessible name stays the plain label.
  • Each shown hint, typed with a trailing space on a top-level empty line, makes the block its row names. For Code Block, type ``` and a space.
  • The "Slash menu popup" entry in .cursor/docs/design-system.md records the hint look.

Blocked by

Agent brief

Type: AFK — an agent can finish this alone.

Category: enhancement

Current behavior:

  • A row has an icon and a label only (apps/webapp/src/components/TipTap/slash/SlashMenuList.tsx:70-71). SlashItem has no hint field (slash/slashMenuSession.ts:8-16).
  • The Slash menu opens in any textblock that is not Title or code, including headings, list items and blockquotes (allow in apps/webapp/src/components/TipTap/extensions/slash-menu/slash-menu.ts:55-61).
  • SlashMenuList already gets the editor prop (slash/SlashMenuList.tsx:14-20). The desktop popup and the phone sheet both render it.
  • The Markdown shortcuts are Tiptap input rules. The pad loads them through StarterKit, TaskList/TaskItem and CodeBlockLowlight (TipTap/TipTap.tsx:107-187). No pad extension overrides them. Each lives in its Tiptap 3.31.3 package source:
    • Heading: ^(#{min,level})\s$, built per level (@tiptap/extension-heading src/heading.ts:144).
    • Bullet: ^\s*([-+*])\s$ (@tiptap/extension-list src/bullet-list/bullet-list.ts:50).
    • Ordered: ^(\d+)\.\s$ (src/ordered-list/ordered-list.ts:61).
    • Task: ^\s*(\[([( |x])?\])\s$ (src/task-item/task-item.ts:75).
    • Blockquote: ^\s*>\s$ (@tiptap/extension-blockquote src/blockquote.tsx:37).
    • Code: ^```([a-z]+)?[\s\n]$ (@tiptap/extension-code-block src/code-block.ts:73).
  • A list item must start with a paragraph (paragraph block*, @tiptap/extension-list src/item/list-item.ts:72), so ## in a list item stays text. A list cannot wrap a heading, so - on a heading line stays text.
  • A blockquote holds block+, so the Markdown shortcuts work inside one. Hints still stay off there, to keep one simple rule: top-level paragraph only.

Desired behavior:

  • Add an optional hint?: string to SlashItem, and set it on the rows above.
  • In SlashMenuList, render the hint only when isTopLevelParagraph(editor) is true and isPhone() is false (isPhone is in slash/slashItems.ts). isTopLevelParagraph is true when the caret's textblock is a paragraph whose parent is doc.
  • The hint is a bare <kbd aria-hidden> at the end of the row, in text-base-content/60. Do not use the daisyUI kbd class: 1. and [] are typed text, not keys.
  • Show the hint without its trailing space.
  • Put data-testid="slash-menu-option-label" on the label span.

Where to start:

Line numbers are hints as of 2026-09-28; the agent searches by symbol.

Rules that apply:

  • AGENTS.md §Test Policy: add no new test. Nothing shipped is broken here.
  • .cursor/docs/design-system.md §Ink ladder: muted hint text is /60. Load the design-system skill before the UI change.
  • CONTEXT.md §Pad tools: the Slash menu entry. Rows stay the same; only the hint is new.
  • CLAUDE.md §Hard invariants (do not violate): one name per thing. Hints add no new name.

Verify:

  • bun run check
  • Start the local stack with make dev-local. Note the webapp port; it is not always 3000. From apps/webapp, run bunx cypress run --spec cypress/e2e/editor/slash/slash-menu.cy.ts --env EDITOR_BASE_URL=http://localhost:<port>. The existing cases must still pass. An option's text now includes its hint, so the have.text checks on Heading rows (slash-menu.cy.ts:77, :108, :137) break. Point those checks at [data-testid="slash-menu-option-label"]. This edits existing checks and adds no new test.
  • Desktop browser on the /editor playground, in light and dark (set data-theme on <html>):
    • On a top-level empty line, type /. The hints show at the row ends.
    • For each hint, type it with a space on a new empty line. Check the block type.
    • On an empty Heading 2 line and in an empty bullet item, type /. No hint shows.
  • In the browser DevTools accessibility tree, check that each option's name is the plain label.
  • Phone: a narrow window does not produce the mobile shell. Use a real phone, or a mobile user agent on a real pad route. Check that no hint shows.

Out of scope

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    EditorTiptap & ProsemirrorUIenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions