Page link
The page link plugin opens a search of your app's pages when you type [[, and inserts the page you pick as an inline link, as in Notion.
createPageLinkPlugin brings Notion’s [[ page links. Typing [[ opens a menu of the pages your app’s search(query) answers; the text typed after it filters them. Picking one replaces [[query with a pageLink atom, a link to the page, and puts the caret after it. The menu is your menu snippet, as the mention’s is.
<script lang="ts">
import { Edytor, createPageLinkPlugin, type PageLinkItem } from 'edytor';
const search = async (query: string) => {
const response = await fetch(`/api/pages?q=${encodeURIComponent(query)}`);
return (await response.json()) as PageLinkItem[];
};
const pageLinks = createPageLinkPlugin({ search, href: (page) => `/pages/${page.id}` });
</script>
<Edytor plugins={[pageLinks]} />
It is not a default plugin: list it in plugins, in every view of a document that holds page links.
Options
search(query, ctx) => PageLinkItem[] | Promise<PageLinkItem[]>
The pages matching the text typed after [[. A promise is a search: the newest query's answer wins, and the menu reads Searching… meanwhile.
(query, ctx) => PageLinkItem[] | Promise<PageLinkItem[]>href?(page) => string | undefined
A page's URL when search answers none, such as /pages/<id>.
(page) => string | undefinedchar?string
The text that opens the menu. Default [[.
stringmenu?Snippet<[TriggerMenuController<PageLinkItem>]>
The menu, at the caret while it is open (without it, nothing shows). Keep its ARIA with {@attach controller.popup} on the list and {@attach controller.option(index)} on each row. See Menus and handles.
Snippet<[TriggerMenuController<PageLinkItem>]>A PageLinkItem is { id, title, href?, icon? }: id is the page’s id in your app, title the text shown, href where the link goes (absolute, or relative to your app) and icon a short icon such as an emoji (default 📄).
The page link atom
A page link is an inline block of type pageLink whose data is { id, title, href?, icon? }:
{ "type": "pageLink", "data": { "id": "p1", "title": "Roadmap", "href": "/pages/p1", "icon": "🗺️" } }
It renders an <a class="edytor-page-link" data-edytor-page-link href="…"> holding the icon (.icon) and the title (.title), with data-selected="true" while the atom is selected (the Notion theme draws the underlined title and the selection), and copies as plain text as its title. The href goes through the link sanitizer when it is stored and when it is rendered: a javascript: or other script URL is dropped, and the atom renders without one. The title is the one stored when it was picked: to show a page’s current title, render your own snippet (pageLinkInlineBlock) that looks it up by data.id.
Behavior
The menu is a trigger of two characters: it opens when the second [ completes [[ at the start of a text or after whitespace. A single [ ([] for a to-do with the markdown shortcuts) opens nothing. ↑/↓ move the highlight, Enter or a click picks, Escape closes it and keeps the text. The pick is one undo step; a refusal keeps [[query. The menu’s listbox is named “Pages”.
For people, see Mention.