
<mastodon-post /> is a Web Component that turns a public Mastodon status URL into an inline post with its content and engagement counts.
You can replace the generated markup with your own HTML template for the page or for individual posts.
Features
- Default quote markup with an author link, reposts, replies, and favorite counts.
- Page-wide template replacement.
- Per-instance templates.
- Nested object and array bindings.
- Multiple bindings on one template node.
- Automatic custom-element registration after the module loads.
How To Use It
Installation
Self-hosted Module
Host mastodon-post.js in your project and load it as a module.
<script type="module" src="/path/to/mastodon-post.js"></script>
npm
Install the package when your project uses npm.
npm install @daviddarnes/mastodon-post
CDN
Load the library from a CDN.
<script type="module" src="https://www.unpkg.com/@daviddarnes/[email protected]/mastodon-post.js" ></script> <script type="module" src="https://esm.sh/@daviddarnes/[email protected]" ></script>
Basic Usage
The original anchor stays inside <mastodon-post>. Hide it after the custom element registers when the generated post should replace the link. If JavaScript never loads, the anchor stays visible.
<style>
mastodon-post:defined > a {
display: none;
}
</style>
<script type="module" src="/path/to/mastodon-post.js"></script>
<mastodon-post>
<a href="https://mastodon.design/@DavidDarnes/109824258017750161">
Discuss on Mastodon
</a>
</mastodon-post>
Default Template
When the page does not define #mastodon-post-template, the module creates this template for the generated post.
<figure>
<blockquote data-key="content"></blockquote>
<figcaption>
<cite>
<a data-key="url">
<span data-key="username"></span>
@
<span data-key="hostname"></span>
</a>
</cite>
<dl>
<dt>Reposts</dt>
<dd data-key="reblogs_count"></dd>
<dt>Replies</dt>
<dd data-key="replies_count"></dd>
<dt>Favourites</dt>
<dd data-key="favourites_count"></dd>
</dl>
</figcaption>
</figure>
Replace the Default Template
Define a <template> with the ID mastodon-post-template to change the markup used by components that do not specify another template.
<template id="mastodon-post-template">
<blockquote data-key="content"></blockquote>
<dl>
<dt>Reposts</dt>
<dd data-key="reblogs_count"></dd>
<dt>Replies</dt>
<dd data-key="replies_count"></dd>
<dt>Favourites</dt>
<dd data-key="favourites_count"></dd>
</dl>
</template>
<mastodon-post>
<a href="https://mastodon.design/@DavidDarnes/109824258017750161">
Discuss on Mastodon
</a>
</mastodon-post>
Use a Different Template for One Post
Set the template attribute to the ID of another <template> when one embed needs different markup.
<template id="compact-post">
<a data-key="content, url"></a>
</template>
<mastodon-post template="compact-post">
<a href="https://mastodon.design/@DavidDarnes/109824258017750161">
Discuss on Mastodon
</a>
</mastodon-post>
Bind Mastodon Status Data
data-key reads fields from the Mastodon Status response. Dot notation reads nested objects. Bracket notation reads array entries. Only bind nested paths that exist in the returned status; the resolver does not guard a missing intermediate object or array item.
For a status with at least one media attachment:
<template id="mastodon-post-template">
<article>
<blockquote data-key="content"></blockquote>
<p>
<img alt="Mastodon account avatar" data-key="account.avatar" />
<strong data-key="account.display_name"></strong>
</p>
<img
alt="Mastodon post media"
data-key="media_attachments[0]preview_url"
/>
<p>
Replies:
<span data-key="replies_count"></span>
</p>
<a data-key="url">View original post</a>
</article>
</template>
Bind Multiple Values to One Element
Separate keys with commas when one template node needs multiple values. Here, content fills the anchor body and url sets its destination.
<template id="linked-post">
<a data-key="content, url"></a>
</template>
<mastodon-post template="linked-post">
<a href="https://mastodon.design/@DavidDarnes/109824258017750161">
Discuss on Mastodon
</a>
</mastodon-post>
Template API Reference
template: Set on<mastodon-post>to select a<template>by ID for that instance.id="mastodon-post-template": Defines the shared custom template when no per-instancetemplatevalue is present.data-key: Maps a Mastodon status field to a template node.- Comma-separated
data-keyvalues: Apply multiple fields to one node. - Nested keys: Read object properties such as
account.display_nameand array entries such asmedia_attachments[0]preview_url. - Link-derived fields: The default template uses
url,username, andhostnamefrom the source Mastodon link.
Value Binding Behavior
contentis assigned toinnerHTML.- A string beginning with
httpsetshrefwhen the receiving node is an<a>. - A string beginning with
httpsetssrcwhen the receiving node is an<img>. - Other values are assigned through
textContent.
Styling
mastodon-post {
display: block;
max-inline-size: max-content;
font-family: system-ui;
}
mastodon-post blockquote {
margin: 0;
border-inline-start: 2px solid currentColor;
padding-inline-start: 1rem;
}
mastodon-post figure {
margin: 0;
}
mastodon-post figcaption,
mastodon-post dl {
display: flex;
flex-wrap: wrap;
align-items: end;
gap: 1rem;
}
mastodon-post dl {
margin: 0;
margin-inline-start: auto;
gap: 0.25rem;
}
Alternatives & Related Resources
- Embed Mastodon Hashtag Feeds on Your Website – FediTag.js
- Display Bluesky Posts with Metadata – bluesky-post.js
- Embed Bluesky Comment Threads Anywhere With bsky-comments
- Rich Link Previews With Link-Peek Web Component






