Attributes, CSS variables, and stable selectors for the preview component.
Load the component once, then use <link-metadata-preview> anywhere you need a card.
<script type="module" src="https://api.linkmetadata.com/component.js" async></script>
<link-metadata-preview data-url="https://example.com/article"></link-metadata-preview>
The component renders inside its own shadow root, so its internal markup does not collide with your page CSS. Presentation is customized through attributes and CSS variables.
On connection, the component follows this order:
data-meta contains valid JSON, render that metadata immediately and skip fetching.data-url exists, render a plain fallback link first.If data-meta is present but invalid, the component logs a console error and falls back to data-url when one is available.
The default API request is:
https://api.linkmetadata.com/v1/metadata?url={encoded data-url}
The API is free to use. Requests made by the component count toward the public per-IP limit: 20 requests per 10 seconds, followed by a 10-second block when the limit is reached.
Multiple component instances with the same request URL share one in-flight fetch. After that request settles, the shared entry is removed; long-lived caching is handled by the browser and the LinkMetadata API.
When an instance is removed from the DOM, changes data-url, or switches to valid data-meta, it releases its active fetch. If no other instance is waiting for that same request, the component aborts the fetch. Stale responses are ignored, so a slow previous URL will not overwrite a newer card.
The component avoids showing technical errors to end users. If the metadata request fails, it keeps a plain linked fallback. If the preview image fails to load, the image area is hidden. If the favicon fails to load, only the favicon is hidden.
Card titles use the first useful value from title, og["og:title"], or twitter["twitter:title"]. If no title exists, the component promotes a short description to the title. If neither title nor description exists, it displays the hostname.
Images that are not marked cors_safe: true are loaded through LinkMetadata’s image proxy. Favicons are proxied only when favicon.cors_safe is explicitly false.
For details on cors_safe, supported proxy formats, and proxy errors, see Images and CORS.
| Attribute | Type / Values | Default | What it does |
|---|---|---|---|
data-url | string | - | The page you want to preview. Required unless data-meta is provided. |
data-theme | "light", "dark", "card" | "light" | Picks one of the preset colour systems. |
data-orientation | "horizontal", "vertical" | "horizontal" | Layout: image on the left vs. image on top. If omitted, narrow screens use vertical layout automatically. |
data-show-image | "true", "false" | "true" | Show or hide the image. |
data-show-favicon | "true", "false" | "true" | Show or hide the favicon next to the title. |
data-show-branding | "true", "false" | "true" | Show or hide the “Preview by LinkMetadata.com” line. |
data-max-width | CSS length | "500px" | Set the maximum card width, for example "720px" or "100%". |
data-image-aspect-ratio | CSS ratio or number | - | Override the image container aspect ratio, for example "16/9" or "1.91". |
data-original-url | string | - | Display this hostname instead of the canonical metadata URL. |
data-api-endpoint | string | https://api.linkmetadata.com/v1/metadata?url= | Prefix used before the encoded data-url. |
data-meta | JSON string | - | Render pre-fetched metadata and skip the component’s API request. |
All attributes are reactive.
Boolean display attributes are string based. Use "false" to disable a feature; any other value behaves like enabled.
Every observed attribute also has a camel-cased property.
| Property | Attribute |
|---|---|
dataUrl | data-url |
dataTheme | data-theme |
dataOrientation | data-orientation |
dataShowImage | data-show-image |
dataShowFavicon | data-show-favicon |
dataShowBranding | data-show-branding |
dataOriginalUrl | data-original-url |
dataApiEndpoint | data-api-endpoint |
dataMaxWidth | data-max-width |
dataImageAspectRatio | data-image-aspect-ratio |
dataMeta | data-meta |
const preview = document.querySelector("link-metadata-preview");
preview.dataUrl = "https://example.com/next";
preview.dataTheme = "card";
preview.dataShowImage = false;
preview.dataMeta = {
title: "Cached title",
description: "Rendered without a client-side API request.",
url: "https://example.com/cached",
image: { url: null },
favicon: { url: null },
og: {},
twitter: {},
safety_tags: []
};
Setting dataMeta to an object serializes it to JSON. Setting it to null removes data-meta; if data-url is present, the component fetches fresh metadata again.
data-orientation="horizontal" puts the image beside the content. data-orientation="vertical" puts the image above the content. If data-orientation is omitted, the component uses horizontal layout on wider screens and switches to vertical below 480px.
Changing layout, theme, image visibility, favicon visibility, branding visibility, max width, or image ratio re-renders the existing metadata without making another API request.
Use data-meta when your backend, cache, or server-side render already has metadata. The component renders the card without making its own API request and still responds to later attribute changes.
For a complete example, see Render pre-fetched metadata.
| Variable | Purpose | Default value |
|---|---|---|
--lm-border | Card border shorthand | 1px solid #d7dce0 |
--lm-radius | Corner radius | 8px (12px in card theme) |
--lm-bg | Card background color | #fff |
--lm-shadow | Base box-shadow | 0 1px 3px 0 rgba(0,0,0,.1), 0 1px 2px 0 rgba(0,0,0,.06) |
--lm-hover-shadow | Shadow on hover | Theme-specific |
--lm-transition | Card transition | box-shadow 0.2s ease-in-out |
--lm-max-width | Maximum card width | 500px |
--lm-font-family | Card font stack | System UI stack |
--lm-content-padding | Text block padding | 12px |
--lm-content-padding-mobile | Text block padding under 480px | 12px |
--lm-title-color | Title text color | #111 |
--lm-title-size | Title font size | 1em |
--lm-title-weight | Title font weight | 600 |
--lm-title-line-height | Title line height | 1.3 |
--lm-title-lines | Maximum title lines | 2 |
--lm-desc-color | Description text color | #444 |
--lm-desc-size | Description font size | 0.875em |
--lm-desc-line-height | Description line height | 1.4 |
--lm-desc-lines | Maximum description lines | 2 |
--lm-url-color | URL line color | #555 |
--lm-url-size | URL line font size | 0.75em |
--lm-branding-color | Branding line color | #777 |
--lm-branding-size | Branding font size | 0.65em |
--lm-branding-padding-top | Space above branding | 8px |
--lm-fallback-bg | Missing-image background | #f0f0f0 |
--lm-fallback-icon-color | Missing-image icon color | #aaa |
--lm-image-width | Thumbnail width in horizontal layout | 120px |
--lm-image-aspect-ratio | Thumbnail aspect ratio | 1.5/1 horizontal, 16/9 vertical |
--lm-image-fit | Thumbnail object-fit | cover |
--lm-image-position | Thumbnail object-position | center |
--lm-favicon-size | Favicon width and height | 16px |
--lm-favicon-gap | Gap between favicon and title | 8px |
These .lm-* selectors are part of the styling contract.
| Selector | What it is |
|---|---|
.lm-card | The anchor that forms the whole card |
.lm-image-container | The thumbnail wrapper |
.lm-default-icon-container | Wrapper shown when image is missing |
.lm-icon-fallback svg | Chain-link SVG shown when image is missing |
.lm-content | Text column |
.lm-title-wrapper | Favicon and title row |
.lm-favicon | Favicon next to the title |
.lm-title | Title line |
.lm-desc | Description line |
.lm-url | Hostname line |
.lm-branding | Branding tagline |