diff --git a/pkgs/docs-site/src/app.html b/pkgs/docs-site/src/app.html
index f273cc58f..adc6da57c 100644
--- a/pkgs/docs-site/src/app.html
+++ b/pkgs/docs-site/src/app.html
@@ -1,11 +1,14 @@
-
-
-
- %sveltekit.head%
-
-
- %sveltekit.body%
-
+
+
+
+
+ %sveltekit.head%
+
+
+ %sveltekit.body%
+
diff --git a/pkgs/docs-site/src/lib/markdown/main.css b/pkgs/docs-site/src/lib/markdown/main.css
index 9241d9544..a95a26557 100644
--- a/pkgs/docs-site/src/lib/markdown/main.css
+++ b/pkgs/docs-site/src/lib/markdown/main.css
@@ -1,5 +1,6 @@
@import url("./shiki.css");
@import url("./admonition.css");
+@import url("./tabs.css");
code {
font-family:
diff --git a/pkgs/docs-site/src/lib/markdown/tabs.css b/pkgs/docs-site/src/lib/markdown/tabs.css
new file mode 100644
index 000000000..6e4ed6618
--- /dev/null
+++ b/pkgs/docs-site/src/lib/markdown/tabs.css
@@ -0,0 +1,50 @@
+.md-tabs-bar {
+ display: none;
+ gap: 7px;
+ align-items: flex-end;
+}
+.md-tabs-tab {
+ padding: 8px 0;
+}
+.md-tabs-container {
+ margin: 20px 0;
+}
+.js {
+ .md-tabs-bar {
+ display: flex;
+ }
+ .md-tabs-container {
+ margin: 0;
+ > .md-tabs-tab {
+ display: none;
+ }
+ }
+ .md-tabs {
+ margin: 20px 0;
+ }
+ .md-tabs-tab {
+ background: #d7dadf;
+ padding: 8px 18px;
+ border-top-left-radius: 8px;
+ border-top-right-radius: 8px;
+ cursor: pointer;
+ &.is-active {
+ background: #eff1f5;
+
+ .md-tabs.is-singleton & {
+ padding: 8px 16px;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+ flex: 1;
+ border-bottom: 1px solid #d8dbe1;
+ }
+ }
+ }
+ .md-tabs-content {
+ display: none;
+ margin: 0 var(--pageMargin);
+ &.is-active {
+ display: block;
+ }
+ }
+}
diff --git a/pkgs/docs-site/src/lib/markdown/vite/index.ts b/pkgs/docs-site/src/lib/markdown/vite/index.ts
index a9c23f2bc..76b1543a7 100644
--- a/pkgs/docs-site/src/lib/markdown/vite/index.ts
+++ b/pkgs/docs-site/src/lib/markdown/vite/index.ts
@@ -17,6 +17,7 @@ import rehypeTocSlug from "./rehype-toc-slug";
import transformerLineNumbers from "./shiki-transformer-line-numbers";
import remarkParse from "./remark-parse";
import remarkAdmonition from "./remark-admonition";
+import remarkTabs from "./remark-tabs";
import rehypeWrapHeadings from "./rehype-wrap-headings";
import remarkLinkMigration from "./link-migration";
@@ -44,6 +45,7 @@ export default function ({
.use(remarkGfm)
.use(remarkDirective)
.use(remarkAdmonition)
+ .use(remarkTabs)
.use(remarkRehype)
.use(rehypeTocSlug, {
tocMaxDepth,
diff --git a/pkgs/docs-site/src/lib/markdown/vite/remark-tabs.ts b/pkgs/docs-site/src/lib/markdown/vite/remark-tabs.ts
new file mode 100644
index 000000000..8893a622b
--- /dev/null
+++ b/pkgs/docs-site/src/lib/markdown/vite/remark-tabs.ts
@@ -0,0 +1,93 @@
+import { visit } from "unist-util-visit";
+import type { Paragraph, Root, Text } from "mdast";
+
+export default function remarkTabs() {
+ return (tree: Root) => {
+ visit(tree, (node) => {
+ if (node.type != "containerDirective" || node.name != "tabs") {
+ return;
+ }
+
+ const data = (node.data ||= {});
+ data.hName = "div";
+ data.hProperties = {
+ className: "md-tabs",
+ };
+ let tabIndex = 0;
+ let tabTitles: string[] = [];
+ for (const [i, child] of node.children.entries()) {
+ if (child.type != "containerDirective" || child.name != "tab") {
+ continue;
+ }
+ let tabTitle: string;
+ if (child.children?.[0].data?.directiveLabel) {
+ const p = child.children.shift() as Paragraph;
+ tabTitle = (p.children[0] as Text).value;
+ } else {
+ tabTitle = "(empty)";
+ }
+ tabTitles.push(tabTitle);
+ node.children[i] = {
+ type: "containerDirective",
+ name: "",
+ data: {
+ hName: "div",
+ hProperties: {
+ className: "md-tabs-container",
+ },
+ },
+ children: [
+ {
+ type: "paragraph",
+ data: {
+ hName: "div",
+ hProperties: {
+ className: `md-tabs-tab ${tabIndex == 0 ? "is-active" : ""}`,
+ },
+ },
+ children: [{ type: "text", value: tabTitle }],
+ },
+ {
+ type: "containerDirective",
+ name: "",
+ data: {
+ hName: "div",
+ hProperties: {
+ className: `md-tabs-content ${tabIndex == 0 ? "is-active" : ""}`,
+ },
+ },
+ children: child.children,
+ },
+ ],
+ };
+ tabIndex++;
+ }
+ if (tabTitles.length === 1) {
+ data.hProperties.className += " is-singleton";
+ }
+ // Add tab bar for when js is enabled
+ node.children = [
+ {
+ type: "paragraph",
+ data: {
+ hName: "div",
+ hProperties: {
+ className: "md-tabs-bar",
+ },
+ },
+ children: tabTitles.map((tabTitle, tabIndex) => ({
+ type: "text",
+ data: {
+ hName: "div",
+ hProperties: {
+ className: `md-tabs-tab ${tabIndex == 0 ? "is-active" : ""}`,
+ },
+ },
+ value: tabTitle,
+ })),
+ },
+ ...node.children,
+ ];
+ });
+ };
+}
diff --git a/pkgs/docs-site/src/routes/+layout.svelte b/pkgs/docs-site/src/routes/+layout.svelte
index f099d830d..5db9e9c22 100644
--- a/pkgs/docs-site/src/routes/+layout.svelte
+++ b/pkgs/docs-site/src/routes/+layout.svelte
@@ -111,7 +111,7 @@
display: flex;
justify-content: space-between;
align-items: center;
- padding: 0 var(--pagePadding);
+ padding: 0 var(--pageMargin);
color: var(--fgInvertedColor);
background: var(--bgInvertedColor);
}
diff --git a/pkgs/docs-site/src/routes/[...path]/+page.svelte b/pkgs/docs-site/src/routes/[...path]/+page.svelte
index 84bb0d1bb..1d9299540 100644
--- a/pkgs/docs-site/src/routes/[...path]/+page.svelte
+++ b/pkgs/docs-site/src/routes/[...path]/+page.svelte
@@ -1,6 +1,7 @@