Dead simple yet powerful gist rendering buddy for your Astro blog.
✅ Uses the standard gist embed script and wraps it in an iframe to avoid blocking the main thread
✅ Lazy loads the gist using IntersectionObserver to improve performance
✅ Allows you to style the gist using your own stylesheet
✅ Fails gracefully when the gist fails to load, showing a link to the gist
✅ Supports rendering a specific file from the gist
✅ Supports adding a caption to the gist
✅ Zero dependencies
✅ Less than 1.5 kB of client JavaScript
# pnpm
pnpm add @kotosha/astro-gist
# npm
npm install @kotosha/astro-gist
# yarn
yarn add @kotosha/astro-gist
You can use it in your Astro blog both in .astro
and .mdx
files. Just import the component and use it with the id
prop:
// YourComponent.astro
---
import Gist from '@kotosha/astro-gist'
---
<div>
<Gist id="your-gist-id" />
</div>
// YourPost.mdx
import Gist from '@kotosha/astro-gist'
Awesome gist here:
<Gist id="your-gist-id" />
You can also pass additional props to customize the component behavior:
Name | Type | Default | Description | Required |
---|---|---|---|---|
id | string | - | Gist ID | ✔️ |
caption | string | - | Caption to display below the gist. If not provided, no caption will be displayed. Caption will only be displayed if the gist is loaded successfully | |
className | string | - | Additional class to add to the figure. Useful for styling | |
file | string | - | File to display from the gist. If not provided, the whole gist will be displayed | |
gistStylesUrl | string | - | URL to the stylesheet to use for styling the gist | |
lazy | boolean | true | Whether to lazy load the gist. Use IntersectionObserver to load the gist when it comes into view. If IntersectionObserver is not supported, the gist will be loaded immediately | |
observerRootMargin | number | 150 | Margin around the root of the IntersectionObserver. The more the margin, the earlier the iframe will be loaded | |
showGistLinkOnError | boolean | true | Whether to show the link to the gist when the gist fails to load |
Gist is rendered as a figure
with an optional figcaption
. You can style it using the className
prop:
<Gist className="cls" id="your-gist-id" />
<style>
.cls {
/* Basic styles here */
}
.cls figcaption {
/* Figcaption styles here */
}
</style>
You can also apply styles based on the loading status using the data-loading-status
attribute:
.cls[data-loading-status='success'] {
/* Success styles here */
}
.cls[data-loading-status='error'] {
/* Error styles here */
}
To style the gist itself, pass the URL to the stylesheet you want to use as the gistStylesUrl
prop:
<Gist id="your-gist-id" gistStylesUrl="/gist-theme.css" />
It might be convenient to use a wrapper component to pass the gistStylesUrl
prop to all gists in your blog:
// GistWrapper.astro
---
import Gist from '@kotosha/astro-gist'
const props = Astro.props;
---
<Gist gistStylesUrl="/gist-theme.css" {...props} />
Astro Gist uses the srcdoc
iframe attribute: when the gist is ready to be rendered, it composes the appropriate srcdoc
and passes it to the iframe. Any HTML attributes added to that iframe's html
tag are preserved, so it's really easy to style your gists according to your app's theme:
// gist.css
html[data-theme="light"] ... {
/* Light theme styles here */
}
html[data-theme="dark"] ... {
/* Dark theme styles here */
}
// Your page
<Gist gistStylesUrl="/gist.css" {...props} />
// Your theme provider
onThemeChange = (theme) => {
document.querySelectorAll('[data-astro-gist-iframe]').forEach(iframe => {
const iframeDocument = iframe.contentWindow?.document || iframe.contentDocument;
// Could be classes. Just anything you can work with from your CSS
iframeDocument.documentElement.dataset.theme = theme
})
}
MIT