editor

Docs › Images and media

Link cards

Show an address as a card with title, description and picture (fetchLinkMeta).

Show an address as a box with title, description and picture. Use it to make a source, a product page or a map stand out.

Try it

Code for this demo

createEditor('#editor', {
  toolbar: 'linkCard link | undo redo',
  // a real site asks its server (see below)
  fetchLinkMeta: async (url) => ({
    title: new URL(url).hostname + ' home page',
    description: 'What the server read from the page: og:title, og:description and og:image.',
    image: 'https://picsum.photos/seed/82/400/240',
  }),
});

Adding one

  • Click Link card (linkCard) and enter an address; a missing https:// is added.
  • Paste an address alone into the text: it goes in as a link, and with fetchLinkMeta set a message offers "Show as a card", which swaps the link for a card. Kakao Map and Naver Map addresses get the offer even without fetchLinkMeta.
  • Kakao Map and Naver Map addresses in the Map / embed code dialog go in as cards.

fetchLinkMeta: getting the details from your server

Browsers can't read pages on other sites, so your server has to fetch the title and picture. Without fetchLinkMeta, or when it returns null, the card shows only the domain.

createEditor('#editor', {
  toolbar: 'board | linkCard',
  fetchLinkMeta: async (url) => {
    const res = await fetch('/api/link-meta?url=' + encodeURIComponent(url));
    return res.ok ? res.json() : null; // { title, description?, image?, siteName? }
  },
});
// Node example: read the page's og: tags
app.get('/api/link-meta', async (req, res) => {
  const url = new URL(req.query.url);
  if (!/^https?:$/.test(url.protocol)) return res.status(400).end();
  const html = await (await fetch(url, { redirect: 'follow' })).text();
  const og = (p) => html.match(new RegExp('<meta[^>]+property=["\']og:' + p + '["\'][^>]+content=["\']([^"\']*)', 'i'))?.[1];
  res.json({
    title: og('title') ?? html.match(/<title>([^<]*)/i)?.[1] ?? url.hostname,
    description: og('description'),
    image: og('image'),
    siteName: og('site_name'),
  });
});

Saved HTML

<div data-link-card="" style="margin: 0.8em 0">
  <a href="https://…" target="_blank" rel="noopener noreferrer" style="display: flex; gap: 14px; …">
    <img src="https://…/og.jpg" alt="" style="width: 120px; height: 90px; object-fit: cover; …">
    <span style="display: block; min-width: 0">
      <strong style="display: block">Title</strong>
      <span style="…">Description</span>
      <span style="…">Site name</span>
    </span>
  </a>
</div>

Titles are cut at 120 characters and descriptions at 160. The picture is used only for http(s) addresses; without a site name the domain shows. Cards open in a new tab, and in the editor a card is one piece.

Where it is

linkCard is in the ⋯ more menu of the board and full presets.

Options

NameTypeDefaultDescription
linkCardtoolbar itemOpens the dialog that makes a card from an address.
fetchLinkMeta(url) => Promise<LinkMeta | null>Gets title, description and picture from your server; when set, pasted addresses offer a card.
LinkMeta.titlestringCard title; the domain when empty.
LinkMeta.descriptionstringDescription (up to 160 characters).
LinkMeta.imagestringPicture address (http/https).
LinkMeta.siteNamestringSmall text at the bottom; the domain when empty.