From 7c8c2c49f3efded08e9755eb98384ab4ecd8f4bd Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Tue, 30 Jun 2026 18:57:30 +0200 Subject: [PATCH 1/4] Add failing E2E test for non-optimized MDX asides bug --- .../no-mdx-optimization/astro.config.mjs | 15 +++++++++++++++ .../fixtures/no-mdx-optimization/package.json | 9 +++++++++ .../no-mdx-optimization/src/content.config.ts | 7 +++++++ .../src/content/docs/asides.mdx | 19 +++++++++++++++++++ .../__e2e__/no-mdx-optimization.test.ts | 15 +++++++++++++++ pnpm-lock.yaml | 9 +++++++++ 6 files changed, 74 insertions(+) create mode 100644 packages/starlight/__e2e__/fixtures/no-mdx-optimization/astro.config.mjs create mode 100644 packages/starlight/__e2e__/fixtures/no-mdx-optimization/package.json create mode 100644 packages/starlight/__e2e__/fixtures/no-mdx-optimization/src/content.config.ts create mode 100644 packages/starlight/__e2e__/fixtures/no-mdx-optimization/src/content/docs/asides.mdx create mode 100644 packages/starlight/__e2e__/no-mdx-optimization.test.ts diff --git a/packages/starlight/__e2e__/fixtures/no-mdx-optimization/astro.config.mjs b/packages/starlight/__e2e__/fixtures/no-mdx-optimization/astro.config.mjs new file mode 100644 index 00000000000..5d063eb8fca --- /dev/null +++ b/packages/starlight/__e2e__/fixtures/no-mdx-optimization/astro.config.mjs @@ -0,0 +1,15 @@ +// @ts-check +import mdx from '@astrojs/mdx'; +import starlight from '@astrojs/starlight'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + integrations: [ + starlight({ + title: 'Basics', + pagefind: false, + }), + // Starlight sets `optimize: true`, so we provide our own copy of the MDX integration to test without optimization. + mdx({ optimize: false }), + ], +}); diff --git a/packages/starlight/__e2e__/fixtures/no-mdx-optimization/package.json b/packages/starlight/__e2e__/fixtures/no-mdx-optimization/package.json new file mode 100644 index 00000000000..390b6be783c --- /dev/null +++ b/packages/starlight/__e2e__/fixtures/no-mdx-optimization/package.json @@ -0,0 +1,9 @@ +{ + "name": "@e2e/no-mdx-optimization", + "version": "0.0.0", + "private": true, + "dependencies": { + "@astrojs/starlight": "workspace:*", + "astro": "^7.0.2" + } +} diff --git a/packages/starlight/__e2e__/fixtures/no-mdx-optimization/src/content.config.ts b/packages/starlight/__e2e__/fixtures/no-mdx-optimization/src/content.config.ts new file mode 100644 index 00000000000..080e5813f72 --- /dev/null +++ b/packages/starlight/__e2e__/fixtures/no-mdx-optimization/src/content.config.ts @@ -0,0 +1,7 @@ +import { docsLoader } from '@astrojs/starlight/loaders'; +import { docsSchema } from '@astrojs/starlight/schema'; +import { defineCollection } from 'astro:content'; + +export const collections = { + docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), +}; diff --git a/packages/starlight/__e2e__/fixtures/no-mdx-optimization/src/content/docs/asides.mdx b/packages/starlight/__e2e__/fixtures/no-mdx-optimization/src/content/docs/asides.mdx new file mode 100644 index 00000000000..a9f631bd73e --- /dev/null +++ b/packages/starlight/__e2e__/fixtures/no-mdx-optimization/src/content/docs/asides.mdx @@ -0,0 +1,19 @@ +--- +title: Asides +--- + +:::note +Directive aside +::: + +:::tip{icon="heart"} +Directive aside with custom icon +::: + +import { Aside } from '@astrojs/starlight/components'; + + + + diff --git a/packages/starlight/__e2e__/no-mdx-optimization.test.ts b/packages/starlight/__e2e__/no-mdx-optimization.test.ts new file mode 100644 index 00000000000..9ff33f23854 --- /dev/null +++ b/packages/starlight/__e2e__/no-mdx-optimization.test.ts @@ -0,0 +1,15 @@ +import { expect, testFactory } from './test-utils'; + +const test = testFactory('./fixtures/no-mdx-optimization/'); + +test.describe('no MDX optimization', () => { + test.describe('asides', () => { + test('asides render an SVG icon', async ({ page, getProdServer }) => { + const starlight = await getProdServer(); + await starlight.goto('/asides/'); + + const asideIconsLocator = page.locator('.starlight-aside__title svg'); + await expect(asideIconsLocator).toHaveCount(4); + }); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 281db62031b..f1bee5817ec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -322,6 +322,15 @@ importers: specifier: ^7.0.2 version: 7.0.2(@astrojs/markdown-remark@7.2.0)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(jiti@2.6.1)(yaml@2.8.3) + packages/starlight/__e2e__/fixtures/no-mdx-optimization: + dependencies: + '@astrojs/starlight': + specifier: workspace:* + version: link:../../.. + astro: + specifier: ^7.0.2 + version: 7.0.2(@astrojs/markdown-remark@7.2.0)(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(jiti@2.6.1)(yaml@2.8.3) + packages/starlight/__e2e__/fixtures/ssr: dependencies: '@astrojs/node': From 7faf5885407fbe45639b7d7cc87643adc8136605 Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Tue, 30 Jun 2026 19:22:01 +0200 Subject: [PATCH 2/4] Add comment with link to issue --- packages/starlight/__e2e__/no-mdx-optimization.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/starlight/__e2e__/no-mdx-optimization.test.ts b/packages/starlight/__e2e__/no-mdx-optimization.test.ts index 9ff33f23854..d66b86ce5d5 100644 --- a/packages/starlight/__e2e__/no-mdx-optimization.test.ts +++ b/packages/starlight/__e2e__/no-mdx-optimization.test.ts @@ -9,6 +9,10 @@ test.describe('no MDX optimization', () => { await starlight.goto('/asides/'); const asideIconsLocator = page.locator('.starlight-aside__title svg'); + + // All four aside instances should have an icon, so we expect four icons to be rendered. + // This checks an issue where SVGs were escaped and rendered as text with MDX optimization + // disabled. See https://github.com/withastro/starlight/pull/3967#issuecomment-4833368829 await expect(asideIconsLocator).toHaveCount(4); }); }); From 9d1d88825617616f73e754db35e837478599f466 Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Tue, 30 Jun 2026 19:45:50 +0200 Subject: [PATCH 3/4] Fix aside icons in MDX files when optimization is disabled See https://github.com/withastro/starlight/pull/3967#issuecomment-4833368829 --- packages/starlight/integrations/satteri.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/starlight/integrations/satteri.ts b/packages/starlight/integrations/satteri.ts index 32a0907d892..7fc25a006ae 100644 --- a/packages/starlight/integrations/satteri.ts +++ b/packages/starlight/integrations/satteri.ts @@ -103,6 +103,15 @@ function satteriAsidesPlugin( const icon = getAsideIcon(variant, node.attributes?.['icon']); const iconSvg = `${icon}`; + // Markdown and MDX require different AST shapes for raw HTML content. + // TODO: replace endsWith check with an official Sätteri API once available. + const iconNode = ctx.fileURL?.pathname.endsWith('.mdx') + ? { + type: 'mdxJsxTextElement', + name: 'Fragment', + attributes: [{ type: 'mdxJsxAttribute', name: 'set:html', value: iconSvg }], + } + : { type: 'html', value: iconSvg }; return paragraphElement( 'aside', @@ -112,7 +121,7 @@ function satteriAsidesPlugin( }, [ paragraphElement('p', { class: 'starlight-aside__title', 'aria-hidden': 'true' }, [ - { type: 'html', value: iconSvg }, + iconNode, ...titleNode, ]), paragraphElement('div', { class: 'starlight-aside__content' }, children), From f1afd3f60f0a453c3894fbfb97bdbc225a019ec1 Mon Sep 17 00:00:00 2001 From: Chris Swithinbank Date: Tue, 30 Jun 2026 19:59:09 +0200 Subject: [PATCH 4/4] Add changeset --- .changeset/tricky-dolls-cover.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/tricky-dolls-cover.md diff --git a/.changeset/tricky-dolls-cover.md b/.changeset/tricky-dolls-cover.md new file mode 100644 index 00000000000..5574c309b9f --- /dev/null +++ b/.changeset/tricky-dolls-cover.md @@ -0,0 +1,5 @@ +--- +'@astrojs/starlight': patch +--- + +Fixes an issue where aside icons were rendered incorrectly in projects where Astro’s MDX integration had optimization disabled