Just Another Astro Markdown — remark plugins, client-side enhancements and styles as a single Astro integration.
- Installation
- Setup
- View Transitions (FOUC fix)
- Integration Options
- MarkdownContent Component
- Theming
- Manual / Advanced Usage
npm install jaamd
# or
npx astro add jaamdAdd the integration to your Astro config:
// astro.config.mjs
import { defineConfig } from "astro/config";
import jaamd from "jaamd";
export default defineConfig({
integrations: [jaamd()],
});Wrap your markdown content with the MarkdownContent component in your layout:
---
// src/layouts/BlogPost.astro
import { MarkdownContent } from "jaamd/components";
---
<MarkdownContent>
<slot />
</MarkdownContent>The integration registers all remark plugins and injects the stylesheet automatically. No other configuration is required.
If you are using Astro's ClientRouter (View Transitions), you may notice a flash of unstyled content when navigating between pages. This happens because the integration injects the stylesheet via injectScript("page", ...), a JS module that runs after the new page content has already been swapped into the DOM.
To fix it, import the stylesheet statically in your layout's frontmatter alongside your other CSS. Astro will bundle it as a <link> in <head>, which persists across navigations and is applied before any render:
---
// In any layout that uses MarkdownContent
import "jaamd/default.css";
import "jaamd/styles.css";
---The duplicate import from injectScript is automatically deduplicated by the browser. No extra weight, no side effects.
jaamd({
selector: ".jaamd-content", // CSS selector for the JS enhancements (see below)
theme: "", // Shiki theme (default "github-light")
noDefault: false, // set true to skip injecting jaamd/default variable fallbacks
plugins: {
codeTabs: true, // :::code-tabs directive blocks
alerts: true, // > [!NOTE] / [!WARNING] blockquote alerts
directive: true, // remark-directive (prerequisite for codeTabs)
},
})selector only controls which element the client-side JS enhancements target at runtime. It does not affect the CSS file, which always uses .jaamd-content.
- When using
<MarkdownContent>leaveselectorat its default. The component always addsjaamd-contentto the wrapper, the CSS targets it, and so does the JS. - When doing manual usage, if you write a completely custom wrapper (e.g.
<div data-md>), setselectorto match it. You will also need to provide your own CSS, since the bundled stylesheet is hardcoded to.jaamd-content.
MarkdownContent is a polymorphic component. It renders as <div> by default and accepts any valid HTML tag via the as prop.
import { MarkdownContent } from "jaamd/components";| Prop | Type | Default | Description |
|---|---|---|---|
as |
HTMLTag |
"div" |
The HTML element to render as. |
class |
string |
— | Extra CSS classes appended to the wrapper. |
| ...rest | — | — | All standard HTML attributes for the chosen as element (e.g. id, data-*, aria-*). |
The jaamd-content class is always present on the wrapper element. It is the selector used by the JS enhancements and must not be removed.
---
import { MarkdownContent } from "jaamd/components";
---
<!-- Default: renders as <div class="jaamd-content"> -->
<MarkdownContent>
<slot />
</MarkdownContent>
<!-- Custom tag: renders as <article class="jaamd-content"> -->
<MarkdownContent as="article">
<slot />
</MarkdownContent>
<!-- Extra classes: renders as <article class="jaamd-content prose mx-auto"> -->
<MarkdownContent as="article" class="prose mx-auto">
<slot />
</MarkdownContent>All styles are driven by CSS custom properties. By default, jaamd/default is automatically injected before the main stylesheet so every variable has a sensible fallback value.
Override any variable on :root or .jaamd-content in your own stylesheet:
:root {
/* core colors */
--jaamd-color-fg: #334155;
--jaamd-color-fg-bright: #0f172a;
--jaamd-color-primary: #6366f1;
--jaamd-color-primary-light: #818cf8;
/* typography */
--jaamd-font-sans: ui-sans-serif, system-ui, sans-serif;
--jaamd-font-mono: ui-monospace, monospace;
--jaamd-font-size: 1rem;
}For the complete list of every available variable with its default value, see src/styles/variables.css.
If you supply your own full variable set and don't want jaamd to inject its defaults, set noDefault: true:
jaamd({ noDefault: true })Import plugins and styles directly, bypassing the integration:
// astro.config.mjs
import { remarkCodeTabs, remarkAlert, remarkDirective } from "jaamd";
export default defineConfig({
markdown: {
remarkPlugins: [remarkAlert, remarkDirective, remarkCodeTabs],
},
});---
import "jaamd/default"; // variable fallbacks — omit if you provide your own
import "jaamd/styles";
---
<div class="jaamd-content">
<slot />
</div>
<script>
import { initMarkdownEnhancements } from "jaamd/client";
function run() { initMarkdownEnhancements(".jaamd-content"); }
run();
document.addEventListener("astro:page-load", run);
</script>You can also import the CSS files directly from .css files or frameworks that prefer bare CSS imports:
@import "jaamd/default.css";
@import "jaamd/styles.css";