diff --git a/.changeset/brave-apples-give.md b/.changeset/brave-apples-give.md
new file mode 100644
index 00000000000..4963ac426cc
--- /dev/null
+++ b/.changeset/brave-apples-give.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/starlight-markdoc': minor
+---
+
+Adds support for the `icon` attribute in the `aside` tag, allowing the use of any of Starlight’s built-in icons.
diff --git a/.changeset/five-flowers-flash.md b/.changeset/five-flowers-flash.md
new file mode 100644
index 00000000000..6e5763bb3a7
--- /dev/null
+++ b/.changeset/five-flowers-flash.md
@@ -0,0 +1,5 @@
+---
+'@astrojs/starlight': minor
+---
+
+Adds support for using any of Starlight’s built-in icons in asides.
diff --git a/docs/src/content/docs/components/asides.mdx b/docs/src/content/docs/components/asides.mdx
index a28375b0d60..e3c0ac8ca3f 100644
--- a/docs/src/content/docs/components/asides.mdx
+++ b/docs/src/content/docs/components/asides.mdx
@@ -132,6 +132,36 @@ A warning aside *with* a custom title.
+### Use custom icons
+
+Override the default aside icons by using the [`icon`](#icon) attribute set to the name of [one of Starlight’s built-in icons](/reference/icons/#all-icons).
+
+
+
+```mdx 'icon="starlight"'
+import { Aside } from '@astrojs/starlight/components';
+
+
+```
+
+
+
+```markdoc 'icon="starlight"'
+{% aside type="tip" icon="starlight" %}
+A warning aside *with* a custom icon.
+{% /aside %}
+```
+
+
+
+
+
+
+
## `
`);
+ await expect(res.code).toMatchFileSnapshot(
+ `./snapshots/generates-aside-${type}-custom-label-and-icon.html`
+ );
+ });
+});
+
test('ignores unknown directive variants', async () => {
const res = await renderMarkdown(`
:::unknown
diff --git a/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-caution-custom-icon.html b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-caution-custom-icon.html
new file mode 100644
index 00000000000..564ad6cd0b4
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-caution-custom-icon.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-caution-custom-label-and-icon.html b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-caution-custom-label-and-icon.html
new file mode 100644
index 00000000000..c60755356c2
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-caution-custom-label-and-icon.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-danger-custom-icon.html b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-danger-custom-icon.html
new file mode 100644
index 00000000000..c276e3797d8
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-danger-custom-icon.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-danger-custom-label-and-icon.html b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-danger-custom-label-and-icon.html
new file mode 100644
index 00000000000..fc8c46aeacf
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-danger-custom-label-and-icon.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-note-custom-icon.html b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-note-custom-icon.html
new file mode 100644
index 00000000000..5727e7be5d2
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-note-custom-icon.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-note-custom-label-and-icon.html b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-note-custom-label-and-icon.html
new file mode 100644
index 00000000000..506831fcdb6
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-note-custom-label-and-icon.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-note-multiple-path-custom-icon.html b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-note-multiple-path-custom-icon.html
new file mode 100644
index 00000000000..35cd1b778a1
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-note-multiple-path-custom-icon.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-tip-custom-icon.html b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-tip-custom-icon.html
new file mode 100644
index 00000000000..6f6e1eb9582
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-tip-custom-icon.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-tip-custom-label-and-icon.html b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-tip-custom-label-and-icon.html
new file mode 100644
index 00000000000..b263140d96d
--- /dev/null
+++ b/packages/starlight/__tests__/remark-rehype/snapshots/generates-aside-tip-custom-label-and-icon.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/starlight/integrations/asides.ts b/packages/starlight/integrations/asides.ts
index 85334d708f6..42e6098d8a1 100644
--- a/packages/starlight/integrations/asides.ts
+++ b/packages/starlight/integrations/asides.ts
@@ -1,7 +1,7 @@
///
import type { AstroConfig, AstroIntegration, AstroUserConfig } from 'astro';
-import { h as _h, s as _s, type Properties } from 'hastscript';
+import { h as _h, s as _s, type Properties, type Result } from 'hastscript';
import type { Node, Paragraph as P, Parent, PhrasingContent, Root } from 'mdast';
import {
type Directives,
@@ -14,8 +14,12 @@ import { toString } from 'mdast-util-to-string';
import remarkDirective from 'remark-directive';
import type { Plugin, Transformer } from 'unified';
import { visit } from 'unist-util-visit';
-import type { HookParameters, StarlightConfig } from '../types';
+import type { HookParameters, StarlightConfig, StarlightIcon } from '../types';
import { getRemarkRehypeDocsCollectionPath, shouldTransformFile } from './remark-rehype-utils';
+import { Icons } from '../components/Icons';
+import { fromHtml } from 'hast-util-from-html';
+import type { Element } from 'hast';
+import { AstroError } from 'astro/errors';
interface AsidesOptions {
starlightConfig: Pick;
@@ -88,6 +92,20 @@ function transformUnhandledDirective(
}
}
+/** Hacky function that generates the children of an mdast SVG tree. */
+function makeSvgChildNodes(children: Result['children']): any[] {
+ const nodes: P[] = [];
+ for (const child of children) {
+ if (child.type !== 'element') continue;
+ nodes.push({
+ type: 'paragraph',
+ data: { hName: child.tagName, hProperties: child.properties },
+ children: makeSvgChildNodes(child.children),
+ });
+ }
+ return nodes;
+}
+
/**
* remark plugin that converts blocks delimited with `:::` into styled
* asides (a.k.a. “callouts”, “admonitions”, etc.). Depends on the
@@ -164,6 +182,7 @@ function remarkAsides(options: AsidesOptions): Plugin<[], Root> {
return;
}
const variant = node.name;
+ const attributes = node.attributes;
if (!isAsideVariant(variant)) return;
// remark-directive converts a container’s “label” to a paragraph added as the head of its
@@ -185,6 +204,19 @@ function remarkAsides(options: AsidesOptions): Plugin<[], Root> {
node.children.splice(0, 1);
}
+ let iconPath = iconPaths[variant];
+
+ if (attributes?.['icon']) {
+ const iconName = attributes['icon'] as StarlightIcon;
+ const icon = Icons[iconName];
+ if (!icon) throwInvalidAsideIconError(iconName);
+ // Omit the root node and return only the first child which is the SVG element.
+ const iconHastTree = fromHtml(``, { fragment: true, space: 'svg' })
+ .children[0] as Element;
+ // Render all SVG child nodes.
+ iconPath = makeSvgChildNodes(iconHastTree.children);
+ }
+
const aside = h(
'aside',
{
@@ -202,7 +234,7 @@ function remarkAsides(options: AsidesOptions): Plugin<[], Root> {
fill: 'currentColor',
class: 'starlight-aside__icon',
},
- iconPaths[variant]
+ iconPath
),
...titleNode,
]),
@@ -221,6 +253,14 @@ function remarkAsides(options: AsidesOptions): Plugin<[], Root> {
type RemarkPlugins = NonNullable['remarkPlugins']>;
+export function throwInvalidAsideIconError(icon: string) {
+ throw new AstroError(
+ 'Invalid aside icon',
+ `An aside custom icon must be set to the name of one of Starlight\’s built-in icons, but received \`${icon}\`.\n\n` +
+ 'See https://starlight.astro.build/reference/icons/#all-icons for a list of available icons.'
+ );
+}
+
export function starlightAsides(options: AsidesOptions): RemarkPlugins {
return [remarkDirective, remarkAsides(options)];
}
diff --git a/packages/starlight/user-components/Aside.astro b/packages/starlight/user-components/Aside.astro
index 785a4f20e83..1a1ab00db94 100644
--- a/packages/starlight/user-components/Aside.astro
+++ b/packages/starlight/user-components/Aside.astro
@@ -1,6 +1,8 @@
---
import { AstroError } from 'astro/errors';
import Icon from './Icon.astro';
+import { Icons, type StarlightIcon } from '../components/Icons';
+import { throwInvalidAsideIconError } from '../integrations/asides';
const asideVariants = ['note', 'tip', 'caution', 'danger'] as const;
const icons = { note: 'information', tip: 'rocket', caution: 'warning', danger: 'error' } as const;
@@ -8,9 +10,10 @@ const icons = { note: 'information', tip: 'rocket', caution: 'warning', danger:
interface Props {
type?: (typeof asideVariants)[number];
title?: string;
+ icon?: StarlightIcon;
}
-let { type = 'note', title } = Astro.props;
+let { type = 'note', title, icon } = Astro.props;
if (!asideVariants.includes(type)) {
throw new AstroError(
@@ -20,6 +23,8 @@ if (!asideVariants.includes(type)) {
);
}
+if (icon && !Icons[icon]) throwInvalidAsideIconError(icon);
+
if (!title) {
title = Astro.locals.t(`aside.${type}`);
}
@@ -27,7 +32,7 @@ if (!title) {