Skip to content

Images and Media

Cookbook: Language Ports · Editors · Markdown · Rich-Text · Accessibility · Existing URLs · This Page

Alap menu items can display images instead of text, show thumbnails on hover, and carry rich metadata for custom interactions.

Live version: https://docs.alap.info/cookbook/images-and-media

Image items

Set the image field on a link to render an image instead of text in the menu:

typescript
allLinks: {
  golden_gate: {
    url: 'https://en.wikipedia.org/wiki/Golden_Gate_Bridge',
    image: 'https://example.com/golden-gate.jpg',
    altText: 'Golden Gate Bridge at sunset',
    tags: ['bridge', 'sf'],
  },
}

The menu renders <img src="..." alt="..."> inside the <a> element instead of a text label. Both label and image can be set — image takes priority in the menu, but label is still available to search patterns and hooks.

Styling image items

Web component:

css
alap-link {
  --alap-img-max-height: 4rem;
  --alap-img-radius: 3px;
}

/* Or via ::part() for more control */
alap-link::part(image) {
  object-fit: cover;
  width: 100%;
}

DOM adapter:

css
#alapelem img {
  max-height: 4rem;
  border-radius: 3px;
  object-fit: cover;
}

Thumbnails (hover previews)

The thumbnail field carries a preview image URL that is not rendered in the menu. It's available to event handlers for building custom hover previews:

typescript
allLinks: {
  golden_gate: {
    url: 'https://en.wikipedia.org/wiki/Golden_Gate_Bridge',
    label: 'Golden Gate Bridge',
    thumbnail: 'https://example.com/golden-gate-thumb.jpg',
    description: 'Iconic suspension bridge spanning the Golden Gate strait',
    tags: ['bridge', 'sf'],
    hooks: ['item-hover'],
  },
}

Building a hover preview

React:

tsx
function PreviewLink({ query, children }) {
  const [preview, setPreview] = useState(null);

  return (
    <>
      <AlapLink
        query={query}
        onItemHover={({ link }) => setPreview(link)}
      >
        {children}
      </AlapLink>
      {preview && (
        <div className="preview-card">
          <img src={preview.thumbnail} alt="" />
          <p>{preview.description}</p>
        </div>
      )}
    </>
  );
}

Vanilla DOM:

typescript
const preview = document.getElementById('preview');

const ui = new AlapUI(config, {
  onItemHover: ({ link }) => {
    if (link.thumbnail) {
      preview.innerHTML = `
        <img src="${link.thumbnail}" alt="" />
        <p>${link.description}</p>
      `;
      preview.hidden = false;
    }
  },
});

Web component (event listener):

javascript
document.addEventListener('alap:item-hover', (e) => {
  const { link } = e.detail;
  if (link.thumbnail) {
    showPreview(link.thumbnail, link.description);
  }
});

Image triggers and placement

When an <img> element is an Alap trigger (DOM mode), the menu is positioned at the click coordinates using a synthetic point rect. The placement engine applies the same compass logic, strategies (flip, clamp, place), and viewport fallback as any other trigger — set data-alap-placement="C" for a centered context-menu feel, or use any other direction.

html
<img class="alap" data-alap-linkitems=".gallery" data-alap-placement="SE">

See Placement for the full guide.

Context menus

Use item-context hooks to build right-click or ArrowRight interactions:

typescript
allLinks: {
  golden_gate: {
    url: 'https://en.wikipedia.org/wiki/Golden_Gate_Bridge',
    label: 'Golden Gate Bridge',
    thumbnail: 'https://example.com/golden-gate-large.jpg',
    description: 'Iconic suspension bridge...',
    hooks: ['item-hover', 'item-context'],
    meta: { location: [37.8199, -122.4783] },
  },
}
typescript
onItemContext: ({ link, event }) => {
  event.preventDefault();
  showContextPopup({
    x: event.pageX,
    y: event.pageY,
    title: link.label,
    image: link.thumbnail,
    description: link.description,
    mapUrl: `https://maps.google.com/?q=${link.meta.location.join(',')}`,
  });
}

The meta field

The meta field is a bag of arbitrary key-value pairs. It's not rendered by any adapter — it's available to protocol handlers, event hooks, and custom code:

typescript
allLinks: {
  devocion: {
    url: 'https://www.devocion.com',
    label: 'Devocion',
    tags: ['coffee', 'nyc'],
    meta: {
      location: [40.6892, -73.9838],
      price: 5,
      rating: 4.8,
      hours: '7am-7pm',
    },
  },
}

Protocol expressions read from meta (e.g., :price:0:10: checks meta.price). Event handlers can display any meta field in custom UI. The shape is yours to define.