diff --git a/CHANGELOG.md b/CHANGELOG.md
index 60573efc..d43222fe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,13 @@
All notable changes to this project will be documented in this file.
+## [1.0.17] - 2026-05-01
+
+### Fixed
+
+- Added TOML language preset to CodeGroup to fix missing icon (#235 by @20syldev)
+- Removed unintended clipboard copy on Accordion open (#234 by @20syldev)
+
## [1.0.16] - 2026-04-17
### Changed
diff --git a/packages/components/package.json b/packages/components/package.json
index 697be17f..4d35e9de 100644
--- a/packages/components/package.json
+++ b/packages/components/package.json
@@ -1,6 +1,6 @@
{
"name": "@mintlify/components",
- "version": "1.0.16",
+ "version": "1.0.17",
"description": "Mintlify open-source UI components",
"type": "module",
"main": "./dist/index.cjs",
diff --git a/packages/components/src/components/accordion/accordion-url-utils.ts b/packages/components/src/components/accordion/accordion-url-utils.ts
index eec4ab1c..65b2e1b3 100644
--- a/packages/components/src/components/accordion/accordion-url-utils.ts
+++ b/packages/components/src/components/accordion/accordion-url-utils.ts
@@ -1,5 +1,4 @@
import isEqual from "lodash/isEqual";
-import { copyToClipboard } from "@/utils/copy-to-clipboard";
const CONNECTING_CHARACTER = ":";
@@ -42,8 +41,6 @@ const updateAndCopyUrl = () => {
const idsString = ids.join(CONNECTING_CHARACTER);
const newUrl = buildHistoryUrl(idsString);
- copyToClipboard(newUrl);
-
window.history.replaceState(
{ ...window.history.state, as: newUrl, url: newUrl },
"",
diff --git a/packages/components/src/components/code-block/code-block.stories.tsx b/packages/components/src/components/code-block/code-block.stories.tsx
index b7dc7ca3..bb303593 100644
--- a/packages/components/src/components/code-block/code-block.stories.tsx
+++ b/packages/components/src/components/code-block/code-block.stories.tsx
@@ -464,3 +464,43 @@ export const WithCustomClassName: Story = {
),
};
+
+export const MDXIndents: Story = {
+ render: () => (
+
+ {`import {
+ a,
+ b,
+ } from 'pkg';
+
+ async function main() {
+ console.log('hello');
+ }`}
+
+ ),
+};
+
+export const MDXIndentsDeeplyNested: Story = {
+ render: () => (
+
+ {`function outer() {
+ function middle() {
+ function inner() {
+ function deepest() {
+ if (true) {
+ for (let i = 0; i < 10; i++) {
+ while (i > 0) {
+ return 42;
+ }
+ }
+ }
+ }
+ return deepest();
+ }
+ return inner();
+ }
+ return middle();
+ }`}
+
+ ),
+};
diff --git a/packages/components/src/components/code-block/code-block.tsx b/packages/components/src/components/code-block/code-block.tsx
index 61ac6772..047d1e0c 100644
--- a/packages/components/src/components/code-block/code-block.tsx
+++ b/packages/components/src/components/code-block/code-block.tsx
@@ -2,8 +2,8 @@ import type { ReactNode, RefObject } from "react";
import { Classes } from "@/constants/selectors";
import { cn } from "@/utils/cn";
-import { getNodeText } from "@/utils/get-node-text";
import type { CodeBlockTheme, CodeStyling } from "@/utils/shiki/code-styling";
+import { getCodeString } from "@/utils/shiki/lib";
import { BaseCodeBlock } from "./base-code-block";
import { CodeHeader } from "./code-header";
@@ -98,7 +98,7 @@ const CodeBlock = function CodeBlock(params: CodeBlockProps) {
copyButtonProps,
} = params;
- const codeString = getNodeText(children);
+ const codeString = getCodeString(children, className, true);
const hasGrayBackgroundContainer = !!filename || !!icon;
return (
diff --git a/packages/components/src/components/code-group/code-group.tsx b/packages/components/src/components/code-group/code-group.tsx
index 6f285ccd..c41ce8ad 100644
--- a/packages/components/src/components/code-group/code-group.tsx
+++ b/packages/components/src/components/code-group/code-group.tsx
@@ -18,8 +18,8 @@ import {
import { Icon as ComponentIcon } from "@/components/icon";
import { Classes } from "@/constants/selectors";
import { cn } from "@/utils/cn";
-import { getNodeText } from "@/utils/get-node-text";
import type { CodeBlockTheme, CodeStyling } from "@/utils/shiki/code-styling";
+import { getCodeString } from "@/utils/shiki/lib";
import { LanguageDropdown } from "./language-dropdown";
@@ -220,7 +220,11 @@ const CodeGroup = ({
{feedbackButton && feedbackButton}
{askAiButton && askAiButton}
diff --git a/packages/components/src/utils/shiki/lib.ts b/packages/components/src/utils/shiki/lib.ts
index 99c9bab0..0accfe7d 100644
--- a/packages/components/src/utils/shiki/lib.ts
+++ b/packages/components/src/utils/shiki/lib.ts
@@ -3,6 +3,14 @@ import { type ReactNode, useMemo } from "react";
import { getNodeText } from "@/utils/get-node-text";
import { SHIKI_CLASSNAME } from "@/utils/shiki/constants";
+const lineIndentRegex = /^( *)/;
+const closingStructureRegex = /^([}\])]|<\/)/;
+
+function getIndent(line: string): number {
+ const match = line.match(lineIndentRegex);
+ return match ? match[1].length : 0;
+}
+
function findShikiClassName(children: unknown): boolean {
if (!children || typeof children !== "object") {
return false;
@@ -37,6 +45,49 @@ function findShikiClassName(children: unknown): boolean {
return false;
}
+function dedentCode(code: string): string {
+ const lines = code.split("\n");
+ if (lines.length <= 1) {
+ return code;
+ }
+
+ const relevantLines = lines.filter((line) => line.trim() !== "");
+ if (relevantLines.length === 0) {
+ return code;
+ }
+
+ const firstLine = relevantLines[0];
+ const lastLine = relevantLines.at(-1) ?? firstLine;
+ const firstIndent = getIndent(firstLine);
+ const lastIndent = getIndent(lastLine);
+ const isTemplatePolluted =
+ firstIndent < lastIndent && closingStructureRegex.test(lastLine.trim());
+
+ if (isTemplatePolluted) {
+ const firstNonEmptyIndex = lines.findIndex((line) => line.trim() !== "");
+ const tail = relevantLines.slice(1);
+ if (tail.length === 0) {
+ return code;
+ }
+ const minIndent = Math.min(...tail.map(getIndent));
+ if (minIndent === 0) {
+ return code;
+ }
+ return lines
+ .map((line, i) =>
+ i <= firstNonEmptyIndex ? line : line.slice(minIndent)
+ )
+ .join("\n");
+ }
+
+ const minIndent = Math.min(...relevantLines.map(getIndent));
+ if (minIndent === 0) {
+ return code;
+ }
+
+ return lines.map((line) => line.slice(minIndent)).join("\n");
+}
+
function getCodeString(
children: ReactNode,
className?: string,
@@ -50,7 +101,7 @@ function getCodeString(
const codeString = getNodeText(children);
- return codeString;
+ return dedentCode(codeString);
}
function calculateCodeLinesFromHtml(html: string | undefined): number {
diff --git a/packages/components/src/utils/shiki/snippet-presets.ts b/packages/components/src/utils/shiki/snippet-presets.ts
index 5041cb74..be19dd81 100644
--- a/packages/components/src/utils/shiki/snippet-presets.ts
+++ b/packages/components/src/utils/shiki/snippet-presets.ts
@@ -10,7 +10,7 @@ type SnippetPreset = {
/** Shiki language for syntax highlighting */
shikiLanguage: string;
/** httpsnippet config for code generation */
- httpSnippet: {
+ httpSnippet?: {
target: string;
client?: string;
};
@@ -145,6 +145,11 @@ const SNIPPET_PRESETS: SnippetPreset[] = [
shikiLanguage: "dart",
httpSnippet: { target: "dart" },
},
+ {
+ key: "toml",
+ displayName: "TOML",
+ shikiLanguage: "yaml",
+ },
];
const presetLookup = new Map();