A Lit web component that fetches and displays webmentions for a given page URL.
See it in action: First npm package — keijilohier.com
<script type="module" src="https://cdn.jsdelivr.net/npm/webmention-feed/cdn/webmention-feed.js"></script>
<webmention-feed
post-url="https://yoursite.com/blog/my-post"
endpoint="https://webmention.io/yoursite.com/webmention"
></webmention-feed>Lit is bundled in — no extra dependencies needed.
npm install webmention-feed litlit is a peer dependency and must be installed alongside the package.
- Sign in at webmention.io with your site URL
- Add this to your site's
<head>:
<link rel="webmention" href="https://webmention.io/yoursite.com/webmention" />- Add the component to each post page, setting
post-urlto the canonical URL of that page:
<webmention-feed
post-url="https://yoursite.com/blog/my-post/"
endpoint="https://webmention.io/yoursite.com/webmention"
></webmention-feed>post-url— the specific page to fetch mentions forendpoint— where the send form POSTs to (your webmention.io inbox). If omitted, the send form is hidden entirelyfetch-endpoint— no need to set this, defaults to webmention.io's API
The component automatically fetches mentions for both yoursite.com and www.yoursite.com to catch both URL variants.
If you self-host your own webmention endpoint, you can point the component at it via fetch-endpoint as long as it returns JF2 format:
<webmention-feed
post-url="https://yoursite.com/blog/my-post/"
endpoint="https://yoursite.com/webmention"
fetch-endpoint="https://yoursite.com/api/mentions.jf2"
></webmention-feed><script type="module" src="/webmention-feed.js"></script>
<webmention-feed
post-url="https://example.com/blog/my-post"
endpoint="https://webmention.io/example.com/webmention"
></webmention-feed>| Attribute | Default | Description |
|---|---|---|
post-url |
— | Canonical URL of the page to fetch mentions for |
endpoint |
— | POST endpoint for submitting new webmentions |
fetch-endpoint |
webmention.io | GET endpoint for fetching mentions (JF2 format) |
per-page |
10 |
Number of replies shown per page |
heading |
"Webmentions" |
Section heading text |
loading-text |
"Loading mentions…" |
Text shown while fetching |
empty-text |
"No mentions yet." |
Text shown when there are no mentions |
send-description |
"Written a response? Send a webmention:" |
Prompt above the send form |
submit-label |
"Send" |
Submit button text |
source-label |
"Your post URL" |
Accessible label for the URL input |
anonymous-label |
"Anonymous" |
Display name when author name is missing |
date-locale |
navigator.language |
BCP 47 locale for formatting reply dates |
| Property | Default | Description |
|---|---|---|
--wm-accent-color |
#2563eb |
Links and button background |
--wm-text-color |
inherit |
Body text |
--wm-border-color |
#6b7280 |
Top separator border |
--wm-reply-bg |
transparent |
Reply card background |
--wm-reply-border-color |
#d1d5db |
Reply card border |
--wm-input-bg |
Canvas |
URL input background (adapts to dark mode) |
--wm-input-border-color |
#9ca3af |
URL input border |
--wm-avatar-bg |
#9ca3af |
Placeholder avatar background |
--wm-button-text-color |
#ffffff |
Send button text |
Target internals with webmention-feed::part(name).
base · heading · send-form · input-label · input · button · list · reactions · stat · replies · reply · reply-meta · avatar · reply-author · reply-author-link · reply-date · reply-link · reply-content · status · pagination · page-button · page-button--prev · page-button--next · page-button--disabled · page-info
webmention-feed::part(pagination) {
justify-content: center;
}
webmention-feed::part(page-button) {
background: transparent;
color: #2563eb;
border: 1px solid currentColor;
}
webmention-feed::part(page-button--disabled) {
opacity: 0.2;
}| Slot | Default | Description |
|---|---|---|
like-icon |
♥ | Icon before the like count |
repost-icon |
↩ | Icon before the repost count |
prev-label |
← Prev | Previous page button label |
next-label |
Next → | Next page button label |
Replies are paginated automatically when there are more than per-page entries. Likes and reposts are always shown as counts and are not paginated.
<webmention-feed
post-url="https://example.com/blog/my-post"
per-page="5"
>
<span slot="prev-label">← Previous</span>
<span slot="next-label">Next →</span>
</webmention-feed>All events bubble and are composed, so they can be listened to on any ancestor element.
| Event | Detail | Description |
|---|---|---|
wm-load |
{ mentions, likeCount, repostCount, replyCount } |
Fired when mentions finish loading |
wm-error |
— | Fired when the fetch fails |
wm-page-change |
{ page, totalPages } |
Fired when the user navigates to a different page |
const feed = document.querySelector('webmention-feed');
feed.addEventListener('wm-load', (e) => {
console.log(`Loaded ${e.detail.replyCount} replies`);
});
feed.addEventListener('wm-error', () => {
console.warn('Failed to load webmentions');
});
feed.addEventListener('wm-page-change', (e) => {
console.log(`Page ${e.detail.page} of ${e.detail.totalPages}`);
});Types are included. Import the class directly for subclassing or type annotations:
import { WebmentionFeed } from 'webmention-feed';
const feed = document.querySelector('webmention-feed') as WebmentionFeed;The element is also registered in HTMLElementTagNameMap, so querySelector and createElement return the correct type automatically:
// Automatically typed as WebmentionFeed
const feed = document.querySelector('webmention-feed');All user-facing strings can be replaced via attributes:
<webmention-feed
post-url="https://example.com/blog/my-post"
heading="Reactions"
loading-text="Fetching responses…"
empty-text="No responses yet."
send-description="Have you written a reply? Send a webmention:"
submit-label="Submit"
source-label="URL of your post"
anonymous-label="Someone"
date-locale="fr-FR"
></webmention-feed>