s; reset UA chrome and keep only the
+ // underline indicator so they render identically in light and dark.
+ border-bottom: 2px solid transparent;
font-family: var(--strapi-font-family-mono);
font-size: 11px;
font-weight: 500;
padding: 9px 12px;
color: var(--strapi-fg-4);
cursor: pointer;
- border-bottom: 2px solid transparent;
- transition: all 0.15s;
+ transition: color 0.15s, border-color 0.15s;
user-select: none;
&:hover {
color: var(--strapi-fg-2);
}
+ &:focus-visible {
+ outline: 2px solid var(--ifm-link-color);
+ outline-offset: -2px;
+ }
+
&--active {
color: var(--strapi-fg-1);
border-bottom-color: var(--strapi-accent);
@@ -442,7 +453,7 @@
display: flex;
align-items: center;
gap: 10px;
- padding: 10px 14px;
+ padding: 6px 8px 6px 14px;
border-bottom: 1px solid var(--strapi-border);
font-family: var(--strapi-font-family-mono);
font-size: 12px;
@@ -481,14 +492,13 @@
color: var(--strapi-fg-2);
}
- // Wraps the so the copy button can anchor to its top-right corner.
- // Reveals the copy button on hover.
&__codeWrap {
position: relative;
- &:hover .copyCodeBtn,
- .copyCodeBtn:focus-visible {
- opacity: 1;
+ // Collapsed state: clip to ~10 lines of code.
+ &--collapsed {
+ max-height: 240px;
+ overflow: hidden;
}
}
@@ -497,24 +507,30 @@
margin: 0;
overflow-x: auto;
background: transparent;
+ font-family: var(--strapi-font-family-mono);
+ font-size: 12.5px;
+ line-height: 1.65;
+ color: var(--strapi-fg-2);
code {
- font-family: var(--strapi-font-family-mono);
- font-size: 12.5px;
- line-height: 1.65;
- color: var(--strapi-fg-2);
+ font-family: inherit;
// Prism/Infima give the inner a solid (white) background; strip it
// so the code block blends with the now-transparent panel.
background: transparent !important;
}
- // Collapsed state: clip to ~10 lines of code.
- &--collapsed {
- max-height: 220px;
- overflow: hidden;
+ // Soft-wrap toggle (the "wrap" action button).
+ &--wrap code {
+ white-space: pre-wrap;
+ word-break: break-word;
}
}
+ // Each highlighted line is its own block so line breaks are preserved.
+ &__line {
+ display: block;
+ }
+
// Fade-out gradient over the bottom of a collapsed response.
&__fade {
position: absolute;
@@ -554,39 +570,73 @@
color: var(--strapi-accent-light);
}
-/* ═══ COPY BUTTON (self-contained, used by CodePanel + ResponsePanel) ═══ */
-.copyCodeBtn {
- position: absolute;
- top: 8px;
- right: 8px;
- z-index: 2;
+/* ═══ CODE ACTIONS (Ask AI · wrap · copy) ═══ */
+// Inline action group sitting in the panel's top bar (URL bar / status header),
+// pushed to the right — the same placement and look as the title-bar buttons on
+// regular code blocks (see src/scss/code-block.scss .code-title-bar).
+.codeActions {
display: flex;
align-items: center;
- justify-content: center;
- width: 30px;
- height: 30px;
- padding: 0;
- border: 1px solid var(--strapi-border);
- border-radius: 6px;
- background: var(--strapi-surface-2);
- color: var(--strapi-fg-2);
+ gap: 4px;
+ margin-left: auto;
+}
+
+// Shared button base for Ask AI / wrap / copy: transparent, low-opacity at
+// rest, solid on hover — matching .code-title-bar .clean-btn / .ai-button.
+%codeActionBase {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 4px 8px;
+ border: none;
+ border-radius: var(--strapi-radius-xs, 4px);
+ background: transparent;
+ color: var(--strapi-fg-3);
+ font-family: var(--strapi-font-family-technical);
+ font-size: 11px;
+ font-weight: 600;
cursor: pointer;
- opacity: 0;
- transition: opacity 0.15s ease-in-out, color 0.15s, border-color 0.15s;
+ opacity: 0.6;
+ transition: opacity 0.15s, background 0.15s;
&:hover {
- color: var(--strapi-fg-1);
- border-color: var(--strapi-border-strong);
+ opacity: 1;
+ background: var(--strapi-surface-3);
}
- &--copied {
+ &:focus-visible {
opacity: 1;
- color: var(--strapi-green);
- border-color: var(--strapi-green);
+ outline: 2px solid var(--ifm-link-color);
+ outline-offset: 1px;
}
- svg {
- display: block;
+ svg { display: block; }
+ i { font-size: 13px; }
+}
+
+.codeActionBtn {
+ @extend %codeActionBase;
+
+ // The Ask AI star uses the primary accent, like elsewhere in the docs.
+ // `.ph-sparkle` is a global (Phosphor) class, so it must be escaped from the
+ // CSS-module local-scope hashing or the rule never matches.
+ :global(.ph-sparkle) {
+ color: var(--strapi-primary-500);
+ }
+
+ &--active {
+ opacity: 1;
+ color: var(--strapi-accent);
+ }
+}
+
+/* ═══ COPY BUTTON (self-contained, used inside .codeActions) ═══ */
+.copyCodeBtn {
+ @extend %codeActionBase;
+
+ &--copied {
+ opacity: 1;
+ color: var(--strapi-green);
}
}
@@ -595,49 +645,81 @@
margin-top: 4px;
}
-.responseTabs {
- display: flex;
+/* ═══ STATUS TABS (accessible segmented control — fixes clickability) ═══ */
+// Rendered as a real role="tablist" of . Styled as a
+// segmented control so the tabs read as clickable at rest, unlike the old
+// pills which looked like decorative badges.
+.statusTabs {
+ display: inline-flex;
gap: 2px;
margin-bottom: 8px;
+ padding: 3px;
+ border: 1px solid var(--strapi-border);
+ border-radius: 8px;
+ background: var(--strapi-surface-2);
}
-.responseTab {
+.statusTab {
+ appearance: none;
+ // Per-status accent carried on a CSS var so the active-state rule doesn't
+ // depend on stacking two CSS-module classes (which hash independently and
+ // don't reliably match a `&.otherClass` selector).
+ --tab-color: var(--strapi-fg-3);
font-family: var(--strapi-font-family-technical);
- font-size: 10px;
+ font-size: 11px;
font-weight: 600;
- padding: 3px 8px;
- border-radius: 5px;
- cursor: pointer;
- transition: all 0.15s;
- text-transform: uppercase;
- letter-spacing: 0.04em;
+ padding: 4px 12px;
+ border-radius: 6px;
border: 1px solid transparent;
- user-select: none;
+ background: transparent;
+ color: var(--strapi-fg-3);
+ cursor: pointer;
+ transition: color 0.15s, background 0.15s, border-color 0.15s, box-shadow 0.15s;
+ letter-spacing: 0.03em;
+ line-height: 1.4;
- &--2xx {
- background: rgba(52, 211, 153, 0.1);
- color: var(--strapi-green);
- }
- &--3xx {
- background: rgba(96, 165, 250, 0.1);
- color: #60a5fa;
- }
- &--4xx {
- background: rgba(248, 113, 113, 0.1);
- color: var(--strapi-red);
+ &--2xx { --tab-color: var(--strapi-green); }
+ &--3xx { --tab-color: #60a5fa; }
+ &--4xx { --tab-color: var(--strapi-red); }
+ &--5xx { --tab-color: var(--strapi-amber); }
+
+ &:hover {
+ background: var(--strapi-surface-3);
+ color: var(--strapi-fg-1);
}
- &--5xx {
- background: rgba(251, 191, 36, 0.1);
- color: var(--strapi-amber);
+
+ &:focus-visible {
+ outline: 2px solid var(--ifm-link-color);
+ outline-offset: 1px;
}
+ // Selected tab lifts onto a solid surface and takes its status accent for
+ // BOTH text and border, so light/dark stay consistent.
&--active {
- &.responseTab--2xx { border-color: var(--strapi-green); }
- &.responseTab--4xx { border-color: var(--strapi-red); }
- &.responseTab--5xx { border-color: var(--strapi-amber); }
+ background: var(--strapi-surface-0);
+ color: var(--tab-color);
+ border-color: var(--tab-color);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}
}
+// The global design-system rule `html[data-theme="dark"] [aria-selected="true"]`
+// forces the label to the primary (blue) color and out-specifies a plain class.
+// Re-assert the status accent with matching-or-higher specificity in both themes
+// so the active status tab's text keeps its own color (no blue-text bug).
+:global(html[data-theme='light']),
+:global(html[data-theme='dark']) {
+ .statusTab--active[aria-selected='true'] {
+ color: var(--tab-color);
+ }
+}
+
+// Wraps the response status tabs + code. The status header sits inside each
+// tab, above the (standard) code block.
+.responses {
+ margin-top: 4px;
+}
+
.responseHeader {
display: flex;
align-items: center;
@@ -670,11 +752,6 @@
&--err { color: var(--strapi-red); }
}
-.responseTime {
- color: var(--strapi-fg-5);
- margin-left: auto;
-}
-
@keyframes apiPulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
diff --git a/docusaurus/src/components/ApiReference/index.js b/docusaurus/src/components/ApiReference/index.js
index c0e7a8b4e6..7220997943 100644
--- a/docusaurus/src/components/ApiReference/index.js
+++ b/docusaurus/src/components/ApiReference/index.js
@@ -2,7 +2,6 @@ export { default as ApiReferencePage } from './ApiReferencePage';
export { default as ApiHeader } from './ApiHeader';
export { default as ApiSidebar } from './ApiSidebar';
export { default as Endpoint } from './Endpoint';
+export { default as Responses, ResponseTab } from './Responses';
export { default as MethodPill } from './MethodPill';
export { default as ParamTable } from './ParamTable';
-export { default as CodePanel } from './CodePanel';
-export { default as ResponsePanel } from './ResponsePanel';
diff --git a/docusaurus/src/theme/MDXComponents.js b/docusaurus/src/theme/MDXComponents.js
index a6fb64fe10..c232c986fd 100644
--- a/docusaurus/src/theme/MDXComponents.js
+++ b/docusaurus/src/theme/MDXComponents.js
@@ -43,6 +43,7 @@ import Checklist, { ChecklistItem } from '../components/Checklist';
import DebugComponent from '../components/DebugComponent';
// V3: API 2-column layout
import Endpoint from '../components/ApiReference/Endpoint';
+import Responses, { ResponseTab } from '../components/ApiReference/Responses';
import StepDetails from '../components/StepDetails/StepDetails';
import NextSteps from '../components/NextSteps/NextSteps';
@@ -111,6 +112,8 @@ export default {
Codemods,
NamingConventions,
Endpoint,
+ Responses,
+ ResponseTab,
StepDetails,
NextSteps,
};
From 1be7f500a484a14f0f7b6b4d9821183e82ef8d22 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Fri, 17 Jul 2026 15:13:34 +0200
Subject: [PATCH 02/55] Remove endpoint bottom border separator
The full-width bottom border under each endpoint fell in an awkward spot below the parameter table. Drop it (and the now-unused isLast prop).
---
docusaurus/src/components/ApiReference/Endpoint.jsx | 2 --
.../src/components/ApiReference/api-reference.module.scss | 2 --
2 files changed, 4 deletions(-)
diff --git a/docusaurus/src/components/ApiReference/Endpoint.jsx b/docusaurus/src/components/ApiReference/Endpoint.jsx
index b72820775d..b905855dd2 100644
--- a/docusaurus/src/components/ApiReference/Endpoint.jsx
+++ b/docusaurus/src/components/ApiReference/Endpoint.jsx
@@ -44,7 +44,6 @@ export default function Endpoint({
description,
params = [],
paramTitle = 'Parameters',
- isLast = false,
children,
}) {
useBrokenLinks().collectAnchor(id);
@@ -55,7 +54,6 @@ export default function Endpoint({
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index fe2fe6ee14..eafaf71551 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -175,8 +175,6 @@
/* ═══ ENDPOINT — 2-column split ═══ */
.endpoint {
- border-bottom: 1px solid var(--strapi-border);
-
/* Full-width header above the 2-column grid */
&__header {
padding: 40px 44px 20px;
From dd4f2d4579475f98d18d82f1a0659aa01ad5c0cf Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Fri, 17 Jul 2026 15:38:23 +0200
Subject: [PATCH 03/55] Remove endpoint horizontal padding and stray param
border
The endpoint header and columns had 44px horizontal padding that pushed content inward and a leftover border under the parameter column. Drop the padding so content spans the available width, add a column gap instead, reduce the header top padding, and remove the extra border.
---
.../ApiReference/api-reference.module.scss | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index eafaf71551..bd2a782b3b 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -177,18 +177,23 @@
.endpoint {
/* Full-width header above the 2-column grid */
&__header {
- padding: 40px 44px 20px;
+ padding: 16px 0 20px;
}
/* 2-column grid: params left, code right */
&__columns {
display: grid;
grid-template-columns: 1fr 1fr;
+ // Space between the two columns instead of large outer padding, so the
+ // block content spans the full available width.
+ gap: 40px;
}
&__desc {
- padding: 24px 44px 40px;
- border-right: 1px solid var(--strapi-border);
+ padding: 24px 0 40px;
+ // An external rule adds a bottom border to direct markdown children; it
+ // draws an unwanted line under the parameter column. Suppress it here.
+ border-bottom: none !important;
}
&__methodRow {
@@ -241,7 +246,7 @@
}
&__code {
- padding: 24px 32px 40px;
+ padding: 24px 0 40px;
// No background tint: the contrast on the code/response column added visual
// noise without purpose. The column blends with the page in light and dark.
position: sticky;
@@ -255,8 +260,7 @@
/* Fallback: code-only layout when there are no params */
&__codeOnly {
- padding: 24px 44px 40px;
- max-width: 720px;
+ padding: 24px 0 40px;
}
}
From a83e671a9ece03f9b124b614b4847d1d7ebac50d Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Fri, 17 Jul 2026 15:43:19 +0200
Subject: [PATCH 04/55] Tighten endpoint spacing and drop column separators
Use a column-only gap so stacked params/code no longer get a large row gap, reduce the code column top padding, and remove the vertical and horizontal separators between the parameter and code columns.
---
.../ApiReference/api-reference.module.scss | 15 +++++++--------
docusaurus/src/scss/_base.scss | 4 ++--
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index bd2a782b3b..d9f9ce24e2 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -184,16 +184,15 @@
&__columns {
display: grid;
grid-template-columns: 1fr 1fr;
- // Space between the two columns instead of large outer padding, so the
- // block content spans the full available width.
- gap: 40px;
+ // Only a COLUMN gap: when the layout linearizes to one column (narrow
+ // width), a plain `gap` would also add a large row gap between the stacked
+ // params and code, on top of their paddings. Keep the vertical spacing to
+ // the paddings alone.
+ column-gap: 40px;
}
&__desc {
- padding: 24px 0 40px;
- // An external rule adds a bottom border to direct markdown children; it
- // draws an unwanted line under the parameter column. Suppress it here.
- border-bottom: none !important;
+ padding: 24px 0 20px;
}
&__methodRow {
@@ -246,7 +245,7 @@
}
&__code {
- padding: 24px 0 40px;
+ padding: 12px 0 40px;
// No background tint: the contrast on the code/response column added visual
// noise without purpose. The column blends with the page in light and dark.
position: sticky;
diff --git a/docusaurus/src/scss/_base.scss b/docusaurus/src/scss/_base.scss
index 912c61fb3d..f03b032547 100644
--- a/docusaurus/src/scss/_base.scss
+++ b/docusaurus/src/scss/_base.scss
@@ -359,7 +359,7 @@ main:has(.api-endpoint-block) {
}
.api-endpoint-block--columns [class*="endpoint__desc"] {
border-right: none;
- border-bottom: 1px solid var(--strapi-border);
+ border-bottom: none;
}
[data-content-width="wide"]:not([data-view-mode="ai"]) .api-endpoint-block--columns [class*="endpoint__columns"],
@@ -368,7 +368,7 @@ main:has(.api-endpoint-block) {
}
[data-content-width="wide"]:not([data-view-mode="ai"]) .api-endpoint-block--columns [class*="endpoint__desc"],
[data-content-width="max"]:not([data-view-mode="ai"]) .api-endpoint-block--columns [class*="endpoint__desc"] {
- border-right: 1px solid var(--strapi-border);
+ border-right: none;
border-bottom: none;
}
From 7497f1886f0a8be4d364c27b13cd4896e1857cd5 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Fri, 17 Jul 2026 15:46:44 +0200
Subject: [PATCH 05/55] Migrate remaining REST endpoints to standard code
blocks
Convert the get, create, update, and delete endpoints on the REST API reference page to the new authoring format (Tabs + fenced code + Responses), and widen the gap between the parameter and code columns.
---
docusaurus/docs/cms/api/rest.md | 343 ++++++++++--------
.../ApiReference/api-reference.module.scss | 2 +-
2 files changed, 190 insertions(+), 155 deletions(-)
diff --git a/docusaurus/docs/cms/api/rest.md b/docusaurus/docs/cms/api/rest.md
index f04023c5e7..bcdad44e92 100644
--- a/docusaurus/docs/cms/api/rest.md
+++ b/docusaurus/docs/cms/api/rest.md
@@ -233,18 +233,21 @@ In Strapi 5, a specific document is reached by its `documentId`.
params={[
{ name: 'pluralApiId', type: 'string', required: true, description: 'Plural API ID of the content-type (e.g. restaurants)' },
{ name: 'documentId', type: 'string', required: true, description: 'Unique document identifier' },
- ]}
- codePath="/api/restaurants/znrlzntu9ei5onjvwfaalu2v"
- codePathHighlights={['restaurants', 'znrlzntu9ei5onjvwfaalu2v']}
- codeTabs={[
- {
- label: 'cURL',
- code: `curl 'http://localhost:1337/api/restaurants/znrlzntu9ei5onjvwfaalu2v' \\
- -H 'Authorization: Bearer '`,
- },
- {
- label: 'JavaScript',
- code: `const response = await fetch(
+ ]}>
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants/znrlzntu9ei5onjvwfaalu2v' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const response = await fetch(
'http://localhost:1337/api/restaurants/znrlzntu9ei5onjvwfaalu2v',
{
headers: {
@@ -252,42 +255,54 @@ In Strapi 5, a specific document is reached by its `documentId`.
},
}
);
-const data = await response.json();`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- time: '12ms',
- body: JSON.stringify({
- data: {
- id: 6,
- documentId: "znrlzntu9ei5onjvwfaalu2v",
- Name: "Biscotte Restaurant",
- Description: [
- {
- type: "paragraph",
- children: [{ type: "text", text: "Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products." }]
- }
- ],
- createdAt: "2024-02-27T10:19:04.953Z",
- updatedAt: "2024-03-05T15:52:05.591Z",
- publishedAt: "2024-03-05T15:52:05.600Z",
- locale: "en"
- },
- meta: {}
- }, null, 2),
- },
- {
- status: 404,
- statusText: 'Not Found',
- body: JSON.stringify({
- error: { status: 404, name: 'NotFoundError', message: 'Document not found' }
- }, null, 2),
- },
- ]}
-/>
+const data = await response.json();
+```
+
+
+
+
+
+
+
+```json
+{
+ "data": {
+ "id": 6,
+ "documentId": "znrlzntu9ei5onjvwfaalu2v",
+ "Name": "Biscotte Restaurant",
+ "Description": [
+ {
+ "type": "paragraph",
+ "children": [{ "type": "text", "text": "Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products." }]
+ }
+ ],
+ "createdAt": "2024-02-27T10:19:04.953Z",
+ "updatedAt": "2024-03-05T15:52:05.591Z",
+ "publishedAt": "2024-03-05T15:52:05.600Z",
+ "locale": "en"
+ },
+ "meta": {}
+}
+```
+
+
+
+
+```json
+{
+ "data": null,
+ "error": {
+ "status": 404,
+ "name": "NotFoundError",
+ "message": "Document not found"
+ }
+}
+```
+
+
+
+
+
### Create a document {#create}
@@ -310,16 +325,16 @@ When you POST a document, each object inside a dynamic zone array must include `
paramTitle="Body Parameters"
params={[
{ name: 'data', type: 'object', required: true, description: 'Object containing the field values for the new document' },
- ]}
- codePath="/api/restaurants"
- codePathHighlights={['restaurants']}
- codeTabs={[
- {
- label: 'cURL',
- code: `curl -X POST \\
- 'http://localhost:1337/api/restaurants' \\
- -H 'Authorization: Bearer ' \\
- -H 'Content-Type: application/json' \\
+ ]}>
+
+
+
+
+```bash
+curl -X POST \
+ 'http://localhost:1337/api/restaurants' \
+ -H 'Authorization: Bearer ' \
+ -H 'Content-Type: application/json' \
-d '{
"data": {
"Name": "Restaurant D",
@@ -330,11 +345,14 @@ When you POST a document, each object inside a dynamic zone array must include `
}
]
}
- }'`,
- },
- {
- label: 'JavaScript',
- code: `const response = await fetch(
+ }'
+```
+
+
+
+
+```js
+const response = await fetch(
'http://localhost:1337/api/restaurants',
{
method: 'POST',
@@ -355,34 +373,39 @@ When you POST a document, each object inside a dynamic zone array must include `
}),
}
);
-const data = await response.json();`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- time: '45ms',
- body: JSON.stringify({
- data: {
- documentId: "bw64dnu97i56nq85106yt4du",
- Name: "Restaurant D",
- Description: [
- {
- type: "paragraph",
- children: [{ type: "text", text: "A very short description goes here." }]
- }
- ],
- createdAt: "2024-03-05T16:44:47.689Z",
- updatedAt: "2024-03-05T16:44:47.689Z",
- publishedAt: "2024-03-05T16:44:47.687Z",
- locale: "en"
- },
- meta: {}
- }, null, 2),
- },
- ]}
-/>
+const data = await response.json();
+```
+
+
+
+
+
+
+
+```json
+{
+ "data": {
+ "documentId": "bw64dnu97i56nq85106yt4du",
+ "Name": "Restaurant D",
+ "Description": [
+ {
+ "type": "paragraph",
+ "children": [{ "type": "text", "text": "A very short description goes here." }]
+ }
+ ],
+ "createdAt": "2024-03-05T16:44:47.689Z",
+ "updatedAt": "2024-03-05T16:44:47.689Z",
+ "publishedAt": "2024-03-05T16:44:47.687Z",
+ "locale": "en"
+ },
+ "meta": {}
+}
+```
+
+
+
+
+
### Update a document {#update}
@@ -404,16 +427,16 @@ Each entry you send for a [dynamic zone](/cms/backend-customization/models#dynam
paramTitle="Body Parameters"
params={[
{ name: 'data', type: 'object', required: true, description: 'Object containing the field values to update' },
- ]}
- codePath="/api/restaurants/hgv1vny5cebq2l3czil1rpb3"
- codePathHighlights={['restaurants', 'hgv1vny5cebq2l3czil1rpb3']}
- codeTabs={[
- {
- label: 'cURL',
- code: `curl -X PUT \\
- 'http://localhost:1337/api/restaurants/hgv1vny5cebq2l3czil1rpb3' \\
- -H 'Authorization: Bearer ' \\
- -H 'Content-Type: application/json' \\
+ ]}>
+
+
+
+
+```bash
+curl -X PUT \
+ 'http://localhost:1337/api/restaurants/hgv1vny5cebq2l3czil1rpb3' \
+ -H 'Authorization: Bearer ' \
+ -H 'Content-Type: application/json' \
-d '{
"data": {
"Name": "BMK Paris Bamako",
@@ -424,11 +447,14 @@ Each entry you send for a [dynamic zone](/cms/backend-customization/models#dynam
}
]
}
- }'`,
- },
- {
- label: 'JavaScript',
- code: `const response = await fetch(
+ }'
+```
+
+
+
+
+```js
+const response = await fetch(
'http://localhost:1337/api/restaurants/hgv1vny5cebq2l3czil1rpb3',
{
method: 'PUT',
@@ -449,35 +475,40 @@ Each entry you send for a [dynamic zone](/cms/backend-customization/models#dynam
}),
}
);
-const data = await response.json();`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- time: '34ms',
- body: JSON.stringify({
- data: {
- id: 9,
- documentId: "hgv1vny5cebq2l3czil1rpb3",
- Name: "BMK Paris Bamako",
- Description: [
- {
- type: "paragraph",
- children: [{ type: "text", text: "A very short description goes here." }]
- }
- ],
- createdAt: "2024-03-06T13:42:05.098Z",
- updatedAt: "2024-03-06T14:16:56.883Z",
- publishedAt: "2024-03-06T14:16:56.895Z",
- locale: "en"
- },
- meta: {}
- }, null, 2),
- },
- ]}
-/>
+const data = await response.json();
+```
+
+
+
+
+
+
+
+```json
+{
+ "data": {
+ "id": 9,
+ "documentId": "hgv1vny5cebq2l3czil1rpb3",
+ "Name": "BMK Paris Bamako",
+ "Description": [
+ {
+ "type": "paragraph",
+ "children": [{ "type": "text", "text": "A very short description goes here." }]
+ }
+ ],
+ "createdAt": "2024-03-06T13:42:05.098Z",
+ "updatedAt": "2024-03-06T14:16:56.883Z",
+ "publishedAt": "2024-03-06T14:16:56.895Z",
+ "locale": "en"
+ },
+ "meta": {}
+}
+```
+
+
+
+
+
### Delete a document {#delete}
@@ -491,19 +522,22 @@ const data = await response.json();`,
params={[
{ name: 'pluralApiId', type: 'string', required: true, description: 'Plural API ID (e.g. restaurants)' },
{ name: 'documentId', type: 'string', required: true, description: 'Document ID of the entry to delete' },
- ]}
- codePath="/api/restaurants/bw64dnu97i56nq85106yt4du"
- codePathHighlights={['restaurants', 'bw64dnu97i56nq85106yt4du']}
- codeTabs={[
- {
- label: 'cURL',
- code: `curl -X DELETE \\
- 'http://localhost:1337/api/restaurants/bw64dnu97i56nq85106yt4du' \\
- -H 'Authorization: Bearer '`,
- },
- {
- label: 'JavaScript',
- code: `const response = await fetch(
+ ]}>
+
+
+
+
+```bash
+curl -X DELETE \
+ 'http://localhost:1337/api/restaurants/bw64dnu97i56nq85106yt4du' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const response = await fetch(
'http://localhost:1337/api/restaurants/bw64dnu97i56nq85106yt4du',
{
method: 'DELETE',
@@ -511,9 +545,10 @@ const data = await response.json();`,
Authorization: 'Bearer ',
},
}
-);`,
- },
- ]}
- responses={[]}
- isLast
-/>
+);
+```
+
+
+
+
+
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index d9f9ce24e2..2023d183f7 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -188,7 +188,7 @@
// width), a plain `gap` would also add a large row gap between the stacked
// params and code, on top of their paddings. Keep the vertical spacing to
// the paddings alone.
- column-gap: 40px;
+ column-gap: 60px;
}
&__desc {
From 88108fb2d3fa824da8427fe455e499370e78b4db Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Fri, 17 Jul 2026 15:55:37 +0200
Subject: [PATCH 06/55] Center tab labels and tidy terminal code block chrome
Vertically center tab labels site-wide by removing the extra bottom padding and using flex centering. In terminal-style code blocks, drop the language (BASH) label and move the copy/wrap buttons up into the title bar next to Ask AI instead of floating over the code.
---
docusaurus/src/scss/code-block.scss | 30 +++++++++++++++++++------
docusaurus/src/scss/tabs.scss | 6 ++++-
docusaurus/src/theme/CodeBlock/index.js | 4 ----
3 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index f14c19edf9..a5afc17cc3 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -314,6 +314,7 @@ pre.prism-code {
.code-block-enhanced {
// The wrapper provides the border, radius, and background
+ position: relative;
border: solid 1px var(--custom-code-block-border-color);
border-radius: var(--strapi-radius-md);
overflow: hidden;
@@ -325,6 +326,12 @@ pre.prism-code {
border-color: var(--strapi-border-accent);
}
+ // Leave room in the title bar so the wrap/copy button group (positioned into
+ // it below) doesn't overlap the "Ask AI" button.
+ .code-title-bar__actions {
+ margin-right: 76px;
+ }
+
// The inner .theme-code-block should not have its own border
.theme-code-block {
border: none !important;
@@ -366,10 +373,23 @@ pre.prism-code {
}
}
- // Docusaurus copy/wrap buttons — show on hover, positioned in code area
+ // Docusaurus copy/wrap buttons: pull them up into the title bar (top-right),
+ // next to the Ask AI button, instead of floating over the code. Anchor the
+ // absolute group to the wrapper (not the inner code content) by neutralizing
+ // the code container's positioning context.
+ [class*="codeBlockContent"],
+ [class*="codeBlockContainer"] {
+ position: static !important;
+ }
+
[class*="buttonGroup"] {
- opacity: 0;
- transition: opacity var(--strapi-duration-fast) var(--strapi-ease);
+ position: absolute !important;
+ top: 9px;
+ right: 16px;
+ z-index: 3;
+ display: flex;
+ gap: 6px;
+ opacity: 1;
.clean-btn {
background: var(--code-title-bar-lang-bg) !important;
@@ -383,10 +403,6 @@ pre.prism-code {
}
}
}
-
- &:hover [class*="buttonGroup"] {
- opacity: 1;
- }
}
/* ──────────────────────────────────────────────────────
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index 5aa7b92a58..317452d169 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -22,7 +22,11 @@
&__item {
border-top: 2px solid transparent;
border-bottom-width: 2px;
- padding-bottom: 18px !important;
+ // Center the label vertically: the fixed 34px item height plus the
+ // symmetric --tabs-item-padding already center the text. (A previous
+ // padding-bottom:18px pushed the label upward inside the active pill.)
+ display: inline-flex;
+ align-items: center;
font-family: var(--strapi-font-family-technical);
font-weight: 600;
font-size: 13px;
diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js
index 67f491ad63..bc7bb59f49 100644
--- a/docusaurus/src/theme/CodeBlock/index.js
+++ b/docusaurus/src/theme/CodeBlock/index.js
@@ -82,7 +82,6 @@ function useInjectAIButton(ref, language, codeContent, showAI) {
// macOS-style title bar for terminal blocks
function TerminalTitleBar({ language, title, showAI, codeContent }) {
- const langLabel = LANG_LABELS[language] || (language ? language.toUpperCase() : '');
const labelText = title || 'terminal';
return (
@@ -109,9 +108,6 @@ function TerminalTitleBar({ language, title, showAI, codeContent }) {
Ask AI
)}
- {langLabel && (
- {langLabel}
- )}
);
From d47bdb12caefef64dece66c93ec4415cc88b2db6 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Fri, 17 Jul 2026 16:02:40 +0200
Subject: [PATCH 07/55] Align terminal title-bar action buttons
The copy/wrap button group in terminal code blocks was oversized and overflowed the title bar. Size it to match the Ask AI button and align it on the same row, inside the bar.
---
docusaurus/src/scss/code-block.scss | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index a5afc17cc3..3d2ae75594 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -384,19 +384,36 @@ pre.prism-code {
[class*="buttonGroup"] {
position: absolute !important;
- top: 9px;
- right: 16px;
+ // The group is anchored to the whole wrapper, so a percentage top would
+ // center it over the entire block. Use a fixed offset that lands it inside
+ // the ~50px title bar, vertically aligned with the Ask AI button.
+ top: 12px;
+ right: 20px;
z-index: 3;
display: flex;
- gap: 6px;
+ align-items: center;
+ gap: 4px;
opacity: 1;
.clean-btn {
background: var(--code-title-bar-lang-bg) !important;
position: static !important;
top: auto !important;
+ // Match the Ask AI button's compact size so both align on one row.
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: auto;
+ height: 26px;
+ min-height: 0;
+ padding: 4px 6px;
border-radius: var(--strapi-radius-xs);
+ svg {
+ width: 15px;
+ height: 15px;
+ }
+
svg, i::before, span {
color: var(--code-title-bar-lang-color) !important;
opacity: 1 !important;
From 0e1cc59e4353aa58568621b21cad411debc5b183 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Fri, 17 Jul 2026 16:11:45 +0200
Subject: [PATCH 08/55] Fix terminal title-bar button alignment
Align the copy/wrap button group to the title bar's right padding and reserve space so the Ask AI button sits just left of it, on the same row, without overflowing the bar.
---
docusaurus/src/scss/code-block.scss | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 3d2ae75594..296dc92f30 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -326,10 +326,12 @@ pre.prism-code {
border-color: var(--strapi-border-accent);
}
- // Leave room in the title bar so the wrap/copy button group (positioned into
- // it below) doesn't overlap the "Ask AI" button.
+ // The title bar's content box is inset ~20px from the wrapper edge. Reserve
+ // room on the right of the actions row (Ask AI) for the absolutely-positioned
+ // copy/wrap group, which is anchored to the wrapper at right:20px (see below),
+ // so Ask AI stops just before it with a small gap.
.code-title-bar__actions {
- margin-right: 76px;
+ margin-right: 44px;
}
// The inner .theme-code-block should not have its own border
@@ -388,6 +390,8 @@ pre.prism-code {
// center it over the entire block. Use a fixed offset that lands it inside
// the ~50px title bar, vertically aligned with the Ask AI button.
top: 12px;
+ // 20px = the wrapper→title-bar content inset, so the button's right edge
+ // aligns with the bar's inner right padding.
right: 20px;
z-index: 3;
display: flex;
From 313e753ec4bbc6136ed4a2d0406cff9347e8199d Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Fri, 17 Jul 2026 16:23:19 +0200
Subject: [PATCH 09/55] Match terminal action buttons to standard code block
style
Style the copy/wrap buttons in terminal code blocks as the same white pill with a neutral border used on regular code blocks, sized and positioned to align with the Ask AI button in both light and dark.
---
docusaurus/src/scss/code-block.scss | 39 ++++++++++++++---------------
1 file changed, 19 insertions(+), 20 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 296dc92f30..24f553e008 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -329,9 +329,10 @@ pre.prism-code {
// The title bar's content box is inset ~20px from the wrapper edge. Reserve
// room on the right of the actions row (Ask AI) for the absolutely-positioned
// copy/wrap group, which is anchored to the wrapper at right:20px (see below),
- // so Ask AI stops just before it with a small gap.
+ // so Ask AI stops just before it with a small gap. Width fits up to two pill
+ // buttons (wrap + copy) plus gaps.
.code-title-bar__actions {
- margin-right: 44px;
+ margin-right: 96px;
}
// The inner .theme-code-block should not have its own border
@@ -387,39 +388,37 @@ pre.prism-code {
[class*="buttonGroup"] {
position: absolute !important;
// The group is anchored to the whole wrapper, so a percentage top would
- // center it over the entire block. Use a fixed offset that lands it inside
- // the ~50px title bar, vertically aligned with the Ask AI button.
- top: 12px;
- // 20px = the wrapper→title-bar content inset, so the button's right edge
+ // center it over the entire block. Use a fixed offset that lands the ~34px
+ // pill buttons inside the ~50px title bar, aligned with the Ask AI button.
+ top: 8px;
+ // 20px = the wrapper→title-bar content inset, so the group's right edge
// aligns with the bar's inner right padding.
right: 20px;
z-index: 3;
display: flex;
align-items: center;
- gap: 4px;
+ gap: 8px;
opacity: 1;
+ // Match the regular (non-terminal) code block buttons exactly: white pill
+ // with a neutral border, so terminal blocks are visually identical to the
+ // rest of the site. Only reset positioning + restore the pill chrome; leave
+ // the icon color to the default so it inverts correctly in dark mode.
.clean-btn {
- background: var(--code-title-bar-lang-bg) !important;
position: static !important;
top: auto !important;
- // Match the Ask AI button's compact size so both align on one row.
display: inline-flex;
align-items: center;
justify-content: center;
- width: auto;
- height: 26px;
- min-height: 0;
- padding: 4px 6px;
- border-radius: var(--strapi-radius-xs);
-
- svg {
- width: 15px;
- height: 15px;
- }
+ padding: 6.4px;
+ background: var(--strapi-neutral-0) !important;
+ border: 1px solid var(--strapi-neutral-200) !important;
+ border-radius: var(--strapi-radius-md) !important;
svg, i::before, span {
- color: var(--code-title-bar-lang-color) !important;
+ // Theme-aware icon color so it stays legible in dark mode (a legacy
+ // rule forces black, which vanishes on the dark pill).
+ color: var(--strapi-fg-1) !important;
opacity: 1 !important;
}
}
From d19138199ae6a95310167265052c3778f0893eae Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 11:49:07 +0200
Subject: [PATCH 10/55] Group terminal action buttons in the title bar
Move the native copy/wrap button group into the title bar's actions row via the CodeBlockWrapper effect, so Ask AI, wrap, and copy sit in one flex row and align naturally without brittle absolute positioning. Style all three as the same white pill used on regular code blocks.
---
docusaurus/src/scss/code-block.scss | 65 ++++++++++---------------
docusaurus/src/theme/CodeBlock/index.js | 20 ++++++++
2 files changed, 45 insertions(+), 40 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 24f553e008..38e6de1f75 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -255,33 +255,33 @@ pre.prism-code {
}
}
- // AI button inside the title bar
+ // AI button inside the title bar — same white pill as the copy/wrap buttons
+ // and the Ask AI button on regular code blocks, so all actions match.
.ai-button {
- padding: 4px 8px;
- display: flex;
+ display: inline-flex;
align-items: center;
- gap: 4px;
+ gap: 6px;
+ height: 34px;
+ padding: 0 10px;
font-size: 11px;
font-weight: 600;
- border-radius: var(--strapi-radius-xs);
+ border-radius: var(--strapi-radius-md) !important;
cursor: pointer;
transition: all var(--strapi-duration-fast) var(--strapi-ease);
- min-height: auto;
- opacity: 0.6;
- background: transparent;
+ background: var(--strapi-neutral-0) !important;
+ border: 1px solid var(--strapi-neutral-200) !important;
&:hover {
- opacity: 1;
- background: var(--code-title-bar-lang-bg);
+ border-color: var(--strapi-border-accent) !important;
}
i {
font-size: 12px;
- color: var(--code-title-bar-lang-color);
+ color: var(--strapi-primary-500);
}
span {
- color: var(--code-title-bar-lang-color);
+ color: var(--strapi-fg-1);
}
}
}
@@ -326,13 +326,13 @@ pre.prism-code {
border-color: var(--strapi-border-accent);
}
- // The title bar's content box is inset ~20px from the wrapper edge. Reserve
- // room on the right of the actions row (Ask AI) for the absolutely-positioned
- // copy/wrap group, which is anchored to the wrapper at right:20px (see below),
- // so Ask AI stops just before it with a small gap. Width fits up to two pill
- // buttons (wrap + copy) plus gaps.
+ // Ask AI + the relocated copy/wrap group share this one flex row, so they
+ // align naturally with no absolute positioning (the buttons are moved into
+ // here by CodeBlockWrapper's relocateButtons effect).
.code-title-bar__actions {
- margin-right: 96px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
}
// The inner .theme-code-block should not have its own border
@@ -376,25 +376,10 @@ pre.prism-code {
}
}
- // Docusaurus copy/wrap buttons: pull them up into the title bar (top-right),
- // next to the Ask AI button, instead of floating over the code. Anchor the
- // absolute group to the wrapper (not the inner code content) by neutralizing
- // the code container's positioning context.
- [class*="codeBlockContent"],
- [class*="codeBlockContainer"] {
- position: static !important;
- }
-
+ // The copy/wrap button group is moved into .code-title-bar__actions (see
+ // CodeBlockWrapper). It flows inline there — no absolute positioning.
[class*="buttonGroup"] {
- position: absolute !important;
- // The group is anchored to the whole wrapper, so a percentage top would
- // center it over the entire block. Use a fixed offset that lands the ~34px
- // pill buttons inside the ~50px title bar, aligned with the Ask AI button.
- top: 8px;
- // 20px = the wrapper→title-bar content inset, so the group's right edge
- // aligns with the bar's inner right padding.
- right: 20px;
- z-index: 3;
+ position: static !important;
display: flex;
align-items: center;
gap: 8px;
@@ -402,22 +387,22 @@ pre.prism-code {
// Match the regular (non-terminal) code block buttons exactly: white pill
// with a neutral border, so terminal blocks are visually identical to the
- // rest of the site. Only reset positioning + restore the pill chrome; leave
- // the icon color to the default so it inverts correctly in dark mode.
+ // rest of the site. Leave the icon color to the default so it inverts
+ // correctly in dark mode.
.clean-btn {
position: static !important;
top: auto !important;
display: inline-flex;
align-items: center;
justify-content: center;
+ width: 34px;
+ height: 34px;
padding: 6.4px;
background: var(--strapi-neutral-0) !important;
border: 1px solid var(--strapi-neutral-200) !important;
border-radius: var(--strapi-radius-md) !important;
svg, i::before, span {
- // Theme-aware icon color so it stays legible in dark mode (a legacy
- // rule forces black, which vanishes on the dark pill).
color: var(--strapi-fg-1) !important;
opacity: 1 !important;
}
diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js
index bc7bb59f49..cb68422675 100644
--- a/docusaurus/src/theme/CodeBlock/index.js
+++ b/docusaurus/src/theme/CodeBlock/index.js
@@ -136,8 +136,28 @@ export default function CodeBlockWrapper(props) {
// Inject a real DOM cursor element into terminal blocks
// (CSS ::after pseudo-elements get their background overridden by parent rules)
const terminalRef = useRef(null);
+
+ // Terminal blocks render their own title bar (with the Ask AI button) as a
+ // sibling of the Docusaurus code block, while the native copy/wrap buttons
+ // live deep inside the code block. Rather than align the two across separate
+ // DOM subtrees with brittle absolute positioning, physically MOVE the native
+ // button group into the title bar's actions container so Ask AI + wrap + copy
+ // sit in one flex row and align naturally.
+ const relocateButtons = useCallback((wrapper) => {
+ if (!wrapper) return;
+ const move = () => {
+ const actions = wrapper.querySelector('.code-title-bar__actions');
+ const group = wrapper.querySelector('[class*="buttonGroup"]');
+ if (!actions || !group) return;
+ if (group.parentElement === actions) return; // already moved
+ actions.appendChild(group);
+ };
+ requestAnimationFrame(() => requestAnimationFrame(move));
+ }, []);
+
const injectCursor = useCallback((node) => {
terminalRef.current = node;
+ if (node) relocateButtons(node);
if (!node) return;
// Find the last token line and append a real cursor span
From a97336c2ebc129fb4cb82fe5dd1d8fdef8885458 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 11:54:24 +0200
Subject: [PATCH 11/55] Reveal terminal action buttons on hover only
Hide the Ask AI / wrap / copy buttons in terminal code blocks at rest and reveal them on hover or focus of the block, matching the behavior of regular code blocks.
---
docusaurus/src/scss/code-block.scss | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 38e6de1f75..0065758f68 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -328,11 +328,19 @@ pre.prism-code {
// Ask AI + the relocated copy/wrap group share this one flex row, so they
// align naturally with no absolute positioning (the buttons are moved into
- // here by CodeBlockWrapper's relocateButtons effect).
+ // here by CodeBlockWrapper's relocateButtons effect). Hidden at rest, shown
+ // on hover/focus of the block — same behavior as regular code blocks.
.code-title-bar__actions {
display: flex;
align-items: center;
gap: 8px;
+ opacity: 0;
+ transition: opacity var(--strapi-duration-fast) var(--strapi-ease);
+ }
+
+ &:hover .code-title-bar__actions,
+ &:focus-within .code-title-bar__actions {
+ opacity: 1;
}
// The inner .theme-code-block should not have its own border
@@ -383,7 +391,8 @@ pre.prism-code {
display: flex;
align-items: center;
gap: 8px;
- opacity: 1;
+ // Visibility is controlled by the parent .code-title-bar__actions
+ // (hidden at rest, shown on hover), so don't force opacity here.
// Match the regular (non-terminal) code block buttons exactly: white pill
// with a neutral border, so terminal blocks are visually identical to the
From 3e0eeff2f2dff46dabd936b6e4a453e8d5911395 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 12:03:40 +0200
Subject: [PATCH 12/55] Revert "Reveal terminal action buttons on hover only"
This reverts commit a97336c2ebc129fb4cb82fe5dd1d8fdef8885458.
---
docusaurus/src/scss/code-block.scss | 13 ++-----------
1 file changed, 2 insertions(+), 11 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 0065758f68..38e6de1f75 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -328,19 +328,11 @@ pre.prism-code {
// Ask AI + the relocated copy/wrap group share this one flex row, so they
// align naturally with no absolute positioning (the buttons are moved into
- // here by CodeBlockWrapper's relocateButtons effect). Hidden at rest, shown
- // on hover/focus of the block — same behavior as regular code blocks.
+ // here by CodeBlockWrapper's relocateButtons effect).
.code-title-bar__actions {
display: flex;
align-items: center;
gap: 8px;
- opacity: 0;
- transition: opacity var(--strapi-duration-fast) var(--strapi-ease);
- }
-
- &:hover .code-title-bar__actions,
- &:focus-within .code-title-bar__actions {
- opacity: 1;
}
// The inner .theme-code-block should not have its own border
@@ -391,8 +383,7 @@ pre.prism-code {
display: flex;
align-items: center;
gap: 8px;
- // Visibility is controlled by the parent .code-title-bar__actions
- // (hidden at rest, shown on hover), so don't force opacity here.
+ opacity: 1;
// Match the regular (non-terminal) code block buttons exactly: white pill
// with a neutral border, so terminal blocks are visually identical to the
From 7907d729a832f495a3c94da9daa2b17880ebd192 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 12:08:18 +0200
Subject: [PATCH 13/55] Reveal terminal action buttons on hover, keep them
opaque
Fade the whole title-bar actions row in on block hover/focus while forcing the individual buttons to full opacity, so the copy button no longer disappears (the legacy .clean-btn opacity:0.6 was making it vanish at rest and fight the reveal).
---
docusaurus/src/scss/code-block.scss | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 38e6de1f75..b3d4816099 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -268,6 +268,8 @@ pre.prism-code {
border-radius: var(--strapi-radius-md) !important;
cursor: pointer;
transition: all var(--strapi-duration-fast) var(--strapi-ease);
+ // Stays opaque; the actions row handles the hover fade.
+ opacity: 1 !important;
background: var(--strapi-neutral-0) !important;
border: 1px solid var(--strapi-neutral-200) !important;
@@ -328,11 +330,19 @@ pre.prism-code {
// Ask AI + the relocated copy/wrap group share this one flex row, so they
// align naturally with no absolute positioning (the buttons are moved into
- // here by CodeBlockWrapper's relocateButtons effect).
+ // here by CodeBlockWrapper's relocateButtons effect). Hidden at rest, shown
+ // when the whole block is hovered/focused — same as regular code blocks.
.code-title-bar__actions {
display: flex;
align-items: center;
gap: 8px;
+ opacity: 0;
+ transition: opacity var(--strapi-duration-fast) var(--strapi-ease);
+ }
+
+ &:hover .code-title-bar__actions,
+ &:focus-within .code-title-bar__actions {
+ opacity: 1;
}
// The inner .theme-code-block should not have its own border
@@ -398,6 +408,9 @@ pre.prism-code {
width: 34px;
height: 34px;
padding: 6.4px;
+ // The button itself stays fully opaque; the whole actions row is what
+ // fades in/out on hover. Overrides the legacy .clean-btn opacity:0.6.
+ opacity: 1 !important;
background: var(--strapi-neutral-0) !important;
border: 1px solid var(--strapi-neutral-200) !important;
border-radius: var(--strapi-radius-md) !important;
From 3277b4c2803f03040687fa80a5e9dd6a9324f66b Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 12:21:13 +0200
Subject: [PATCH 14/55] Fix code block action button hover and rest states
On hover the Ask AI button now only darkens its label and icon (no background/border change) on both terminal and regular code blocks. The terminal copy/wrap icons are dimmed at rest (opacity 0.6) and go full opacity on hover, matching the reference buttons instead of showing solid black at rest.
---
docusaurus/src/scss/code-block.scss | 38 ++++++++++++++++++++++++-----
1 file changed, 32 insertions(+), 6 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index b3d4816099..d9d95de1eb 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -273,10 +273,6 @@ pre.prism-code {
background: var(--strapi-neutral-0) !important;
border: 1px solid var(--strapi-neutral-200) !important;
- &:hover {
- border-color: var(--strapi-border-accent) !important;
- }
-
i {
font-size: 12px;
color: var(--strapi-primary-500);
@@ -285,6 +281,21 @@ pre.prism-code {
span {
color: var(--strapi-fg-1);
}
+
+ // On hover only darken the label + icon; keep background and border as-is.
+ // The button also carries the `clean-btn` class, whose legacy :hover would
+ // otherwise tint the background grey — override it explicitly.
+ &:hover {
+ background: var(--strapi-neutral-0) !important;
+
+ i {
+ color: var(--strapi-primary-700) !important;
+ }
+
+ span {
+ color: var(--strapi-neutral-800) !important;
+ }
+ }
}
}
@@ -415,8 +426,18 @@ pre.prism-code {
border: 1px solid var(--strapi-neutral-200) !important;
border-radius: var(--strapi-radius-md) !important;
+ // Match the reference copy/wrap buttons: the icon is dimmed at rest
+ // (opacity 0.6) and goes full opacity on hover — this is what makes it
+ // look grey rather than solid black. !important beats the legacy
+ // opacity:1 rules on .clean-btn icons.
svg, i::before, span {
color: var(--strapi-fg-1) !important;
+ opacity: 0.6 !important;
+ }
+
+ &:hover svg,
+ &:hover i::before,
+ &:hover span {
opacity: 1 !important;
}
}
@@ -618,11 +639,16 @@ pre.prism-code {
font-weight: 600;
}
+ // On hover only darken the label + icon; keep the background unchanged.
+ // !important overrides the more specific .theme-code-block .clean-btn color
+ // rules (these buttons also carry the clean-btn class).
&:hover {
- background: var(--strapi-primary-100);
+ i {
+ color: var(--strapi-primary-700) !important;
+ }
span {
- color: var(--strapi-primary-600);
+ color: var(--strapi-neutral-800) !important;
}
}
}
From 72f1093f4a840f6734a86e725e00041cf92cbdd7 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 12:28:18 +0200
Subject: [PATCH 15/55] Dim terminal Ask AI button icon and label at rest
The Ask AI button in terminal blocks now dims its icon and label to opacity 0.6 at rest (matching the copy/wrap icons) and brings them to full opacity on hover, so it is no longer over-emphasized in dark mode.
---
docusaurus/src/scss/code-block.scss | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index d9d95de1eb..4f4ebd1952 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -273,27 +273,34 @@ pre.prism-code {
background: var(--strapi-neutral-0) !important;
border: 1px solid var(--strapi-neutral-200) !important;
+ // Dimmed at rest (like the copy/wrap icons), full opacity on hover.
+ // !important beats the legacy .clean-btn opacity:1 rules (this button also
+ // carries the clean-btn class).
i {
font-size: 12px;
color: var(--strapi-primary-500);
+ opacity: 0.6 !important;
}
span {
color: var(--strapi-fg-1);
+ opacity: 0.6 !important;
}
- // On hover only darken the label + icon; keep background and border as-is.
- // The button also carries the `clean-btn` class, whose legacy :hover would
- // otherwise tint the background grey — override it explicitly.
+ // On hover only darken the label + icon and bring them to full opacity;
+ // keep background and border as-is. The button also carries the `clean-btn`
+ // class, whose legacy :hover would otherwise tint the background grey.
&:hover {
background: var(--strapi-neutral-0) !important;
i {
color: var(--strapi-primary-700) !important;
+ opacity: 1 !important;
}
span {
color: var(--strapi-neutral-800) !important;
+ opacity: 1 !important;
}
}
}
From 1afb8f5d87c8a2997bbcba843bc915fd48081aa8 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 17:26:30 +0200
Subject: [PATCH 16/55] Migrate REST status and populate-select pages to
standard code blocks
Convert the Endpoint blocks on the REST status and populate-select pages to the new authoring format (Tabs + fenced code + Responses).
---
.../docs/cms/api/rest/populate-select.md | 266 ++++++++++--------
docusaurus/docs/cms/api/rest/status.md | 112 ++++----
2 files changed, 209 insertions(+), 169 deletions(-)
diff --git a/docusaurus/docs/cms/api/rest/populate-select.md b/docusaurus/docs/cms/api/rest/populate-select.md
index b948349d2c..89be62c3c6 100644
--- a/docusaurus/docs/cms/api/rest/populate-select.md
+++ b/docusaurus/docs/cms/api/rest/populate-select.md
@@ -54,17 +54,21 @@ Field selection does not work on relational, media, component, or dynamic zone f
id="field-selection-example"
method="GET"
path="/api/restaurants?fields[0]=name&fields[1]=description"
- codePath="/api/restaurants?fields[0]=name&fields[1]=description"
title="Return only name and description fields"
- description="Use the fields parameter to select only specific fields in the response."
- codeTabs={[
- {
- label: 'URL',
- code: `GET /api/restaurants?fields[0]=name&fields[1]=description`,
- },
- {
- label: 'JavaScript',
- code: `const qs = require('qs');
+ description="Use the fields parameter to select only specific fields in the response.">
+
+
+
+
+```bash
+GET /api/restaurants?fields[0]=name&fields[1]=description
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify(
{
fields: ['name', 'description'],
@@ -74,44 +78,50 @@ const query = qs.stringify(
}
);
-await request(\`/api/users?\${query}\`);`,
- },
- ]}
- responses={[
+await request(`/api/users?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
+ "data": [
{
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: [
- {
- id: 4,
- Name: "Pizzeria Arrivederci",
- Description: [
- {
- type: "paragraph",
- children: [
- {
- type: "text",
- text: "Specialized in pizza, we invite you to rediscover our classics, such as 4 Formaggi or Calzone, and our original creations such as Do Luigi or Nduja."
- }
- ]
- }
- ],
- documentId: "lr5wju2og49bf820kj9kz8c3"
- }
- ],
- meta: {
- pagination: {
- page: 1,
- pageSize: 25,
- pageCount: 1,
- total: 4
- }
+ "id": 4,
+ "Name": "Pizzeria Arrivederci",
+ "Description": [
+ {
+ "type": "paragraph",
+ "children": [
+ {
+ "type": "text",
+ "text": "Specialized in pizza, we invite you to rediscover our classics, such as 4 Formaggi or Calzone, and our original creations such as Do Luigi or Nduja."
+ }
+ ]
}
- }, null, 2),
- },
- ]}
-/>
+ ],
+ "documentId": "lr5wju2og49bf820kj9kz8c3"
+ }
+ ],
+ "meta": {
+ "pagination": {
+ "page": 1,
+ "pageSize": 25,
+ "pageCount": 1,
+ "total": 4
+ }
+ }
+}
+```
+
+
+
+
+
## Population
@@ -163,17 +173,21 @@ Top-level pagination parameters (e.g., `pagination[page]` and `pagination[pageSi
+
+
+
+
+```bash
+GET /api/articles?fields[0]=title&fields[1]=slug&populate[headerImage][fields][0]=name&populate[headerImage][fields][1]=url
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify(
{
fields: ['title', 'slug'],
@@ -188,33 +202,39 @@ const query = qs.stringify(
}
);
-await request(\`/api/articles?\${query}\`);`,
- },
- ]}
- responses={[
+await request(`/api/articles?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
+ "data": [
{
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: [
- {
- id: 1,
- documentId: "h90lgohlzfpjf3bvan72mzll",
- title: "Test Article",
- slug: "test-article",
- headerImage: {
- id: 1,
- documentId: "cf07g1dbusqr8mzmlbqvlegx",
- name: "17520.jpg",
- url: "/uploads/17520_73c601c014.jpg"
- }
- }
- ],
- meta: {}
- }, null, 2),
- },
- ]}
-/>
+ "id": 1,
+ "documentId": "h90lgohlzfpjf3bvan72mzll",
+ "title": "Test Article",
+ "slug": "test-article",
+ "headerImage": {
+ "id": 1,
+ "documentId": "cf07g1dbusqr8mzmlbqvlegx",
+ "name": "17520.jpg",
+ "url": "/uploads/17520_73c601c014.jpg"
+ }
+ }
+ ],
+ "meta": {}
+}
+```
+
+
+
+
+
#### Populate with filtering
@@ -223,17 +243,21 @@ await request(\`/api/articles?\${query}\`);`,
+
+
+
+
+```bash
+GET /api/articles?populate[categories][sort][0]=name%3Aasc&populate[categories][filters][name][$eq]=Cars
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify(
{
populate: {
@@ -252,35 +276,41 @@ const query = qs.stringify(
}
);
-await request(\`/api/articles?\${query}\`);`,
- },
- ]}
- responses={[
+await request(`/api/articles?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
+ "data": [
{
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: [
+ "id": 1,
+ "documentId": "a1b2c3d4e5d6f7g8h9i0jkl",
+ "title": "Test Article",
+ "categories": {
+ "data": [
{
- id: 1,
- documentId: "a1b2c3d4e5d6f7g8h9i0jkl",
- title: "Test Article",
- categories: {
- data: [
- {
- id: 2,
- documentId: "jKd8djla9ndalk98hflj3",
- name: "Cars"
- }
- ]
- }
+ "id": 2,
+ "documentId": "jKd8djla9ndalk98hflj3",
+ "name": "Cars"
}
- ],
- meta: {}
- }, null, 2),
- },
- ]}
-/>
+ ]
+ }
+ }
+ ],
+ "meta": {}
+}
+```
+
+
+
+
+
:::note
For many-to-many and other join-table relations, an explicit `sort` within a `populate` object overrides the default connect order. Omit `sort` to preserve the connect order (the order in which entries were associated).
diff --git a/docusaurus/docs/cms/api/rest/status.md b/docusaurus/docs/cms/api/rest/status.md
index ec3e1a7793..0ef80ea627 100644
--- a/docusaurus/docs/cms/api/rest/status.md
+++ b/docusaurus/docs/cms/api/rest/status.md
@@ -55,63 +55,73 @@ To select documents by how their draft and published versions relate (never-publ
id="get-draft-versions"
method="GET"
path="/api/articles?status=draft"
- codePath="/api/articles?status=draft"
title="Get draft versions of restaurants"
- description="Returns draft versions of documents by passing the status=draft query parameter."
- codeTabs={[
- {
- label: 'cURL',
- code: `curl 'http://localhost:1337/api/articles?status=draft' \\
- -H 'Authorization: Bearer
'`,
- },
- {
- label: 'JavaScript',
- code: `const qs = require('qs');
+ description="Returns draft versions of documents by passing the status=draft query parameter.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/articles?status=draft' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
status: 'draft',
}, {
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/articles?\${query}\`);`,
- },
- ]}
- responses={[
+await request(`/api/articles?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
+ "data": [
{
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: [
- {
- id: 5,
- documentId: "znrlzntu9ei5onjvwfaalu2v",
- Name: "Biscotte Restaurant",
- Description: [
- {
- type: "paragraph",
- children: [
- {
- type: "text",
- text: "This is the draft version."
- }
- ]
- }
- ],
- createdAt: "2024-03-06T13:43:30.172Z",
- updatedAt: "2024-03-06T21:38:46.353Z",
- publishedAt: null,
- locale: "en"
- }
- ],
- meta: {
- pagination: {
- page: 1,
- pageSize: 25,
- pageCount: 1,
- total: 4
- }
+ "id": 5,
+ "documentId": "znrlzntu9ei5onjvwfaalu2v",
+ "Name": "Biscotte Restaurant",
+ "Description": [
+ {
+ "type": "paragraph",
+ "children": [
+ {
+ "type": "text",
+ "text": "This is the draft version."
+ }
+ ]
}
- }, null, 2),
- },
- ]}
-/>
+ ],
+ "createdAt": "2024-03-06T13:43:30.172Z",
+ "updatedAt": "2024-03-06T21:38:46.353Z",
+ "publishedAt": null,
+ "locale": "en"
+ }
+ ],
+ "meta": {
+ "pagination": {
+ "page": 1,
+ "pageSize": 25,
+ "pageCount": 1,
+ "total": 4
+ }
+ }
+}
+```
+
+
+
+
+
From cea6b5d12ccbb57e22742d679939406e4ff482ad Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 17:32:03 +0200
Subject: [PATCH 17/55] Migrate REST filters and sort-pagination pages to
standard code blocks
Convert the Endpoint blocks on the REST filters and sort-and-pagination pages to the new authoring format (Tabs + fenced code + Responses).
---
docusaurus/docs/cms/api/rest/filters.md | 217 +++++++++++-------
.../docs/cms/api/rest/sort-pagination.md | 216 ++++++++++-------
2 files changed, 256 insertions(+), 177 deletions(-)
diff --git a/docusaurus/docs/cms/api/rest/filters.md b/docusaurus/docs/cms/api/rest/filters.md
index 7ec5847760..22bf630cc2 100644
--- a/docusaurus/docs/cms/api/rest/filters.md
+++ b/docusaurus/docs/cms/api/rest/filters.md
@@ -90,17 +90,21 @@ By default, the filters can only be used from `find` endpoints generated by the
id="find-users-eq"
method="GET"
path="/api/users?filters[username][$eq]=John"
- codePath="/api/users?filters[username][$eq]=John"
title="Find users having 'John' as first name"
- description="Use the $eq filter operator to find an exact match."
- codeTabs={[
- {
- label: 'cURL',
- code: `GET /api/users?filters[username][$eq]=John`,
- },
- {
- label: 'JavaScript',
- code: `const qs = require('qs');
+ description="Use the $eq filter operator to find an exact match.">
+
+
+
+
+```bash
+GET /api/users?filters[username][$eq]=John
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
filters: {
username: {
@@ -111,14 +115,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/users?\${query}\`);`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- body: `{
+await request(`/api/users?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -140,10 +147,13 @@ await request(\`/api/users?\${query}\`);`,
"total": 1
}
}
-}`,
- },
- ]}
-/>
+}
+```
+
+
+
+
+
## Example: Find multiple restaurants with ids 3, 6,8
@@ -151,17 +161,21 @@ await request(\`/api/users?\${query}\`);`,
id="find-restaurants-in"
method="GET"
path="/api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8"
- codePath="/api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8"
title="Find multiple restaurants with ids 3, 6, 8"
- description="Use the $in filter operator with an array of values to find multiple exact values."
- codeTabs={[
- {
- label: 'cURL',
- code: `GET /api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8`,
- },
- {
- label: 'JavaScript',
- code: `const qs = require('qs');
+ description="Use the $in filter operator with an array of values to find multiple exact values.">
+
+
+
+
+```bash
+GET /api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
filters: {
id: {
@@ -172,14 +186,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"id": 3,
@@ -198,27 +215,34 @@ await request(\`/api/restaurants?\${query}\`);`,
}
],
"meta": {}
-}`,
- },
- ]}
-/>
+}
+```
+
+
+
+
+
## Complex filtering
+
+
+
+
+```bash
+GET /api/books?filters[$and][0][$or][0][date][$eq]=2020-01-01&filters[$and][0][$or][1][date][$eq]=2020-01-02&filters[$and][1][author][name][$eq]=Kai%20doe
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
filters: {
$and: [
@@ -249,14 +273,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/books?\${query}\`);`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- body: `{
+await request(`/api/books?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -272,10 +299,13 @@ await request(\`/api/books?\${query}\`);`,
}
],
"meta": {}
-}`,
- },
- ]}
-/>
+}
+```
+
+
+
+
+
:::note
The response above only contains a book's own attributes. The `author` relation traversed by the `$and` filter is not returned unless requested through the [`populate` parameter](/cms/api/rest/populate-select#population), for example by adding `&populate=author` to the request.
@@ -297,17 +327,21 @@ Querying your API with deep filters may cause performance issues. If one of you
+
+
+
+
+```bash
+GET /api/restaurants?filters[chef][restaurants][stars][$eq]=5
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
filters: {
chef: {
@@ -322,14 +356,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -345,11 +382,13 @@ await request(\`/api/restaurants?\${query}\`);`,
}
],
"meta": {}
-}`,
- },
- ]}
- isLast
-/>
+}
+```
+
+
+
+
+
:::note
The response above mirrors the default REST output, which excludes the relations traversed by the filter. Add a [`populate` parameter](/cms/api/rest/populate-select#population) such as `&populate[chef][populate][restaurants]=true` to also return the `chef.restaurants` relation referenced in the filter.
diff --git a/docusaurus/docs/cms/api/rest/sort-pagination.md b/docusaurus/docs/cms/api/rest/sort-pagination.md
index d9eceaa638..4cc0ee1c99 100644
--- a/docusaurus/docs/cms/api/rest/sort-pagination.md
+++ b/docusaurus/docs/cms/api/rest/sort-pagination.md
@@ -58,31 +58,38 @@ You can sort by multiple fields by passing fields in a `sort` array.
id="sort-using-2-fields"
method="GET"
path="/api/restaurants?sort[0]=Description&sort[1]=Name"
- codePath="/api/restaurants?sort[0]=Description&sort[1]=Name"
title="Sort using 2 fields"
- description="Sort results by Description and Name fields."
- codeTabs={[
- {
- label: "REST",
- code: `GET /api/restaurants?sort[0]=Description&sort[1]=Name`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Sort results by Description and Name fields.">
+
+
+
+
+```bash
+GET /api/restaurants?sort[0]=Description&sort[1]=Name
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
sort: ['Description', 'Name'],
}, {
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"id": 9,
@@ -123,10 +130,13 @@ await request(\`/api/restaurants?\${query}\`);`
"meta": {
// …
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Example: Sort using 2 fields and set the order
@@ -136,31 +146,38 @@ Using the `sort` parameter and defining `:asc` or `:desc` on sorted fields, you
id="sort-using-2-fields-and-set-the-order"
method="GET"
path="/api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc"
- codePath="/api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc"
title="Sort using 2 fields and set the order"
- description="Sort results by Description ascending and Name descending."
- codeTabs={[
- {
- label: "REST",
- code: `GET /api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Sort results by Description ascending and Name descending.">
+
+
+
+
+```bash
+GET /api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
sort: ['Description:asc', 'Name:desc'],
}, {
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"id": 8,
@@ -201,10 +218,13 @@ await request(\`/api/restaurants?\${query}\`);`
"meta": {
// …
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
## Pagination
@@ -230,17 +250,21 @@ To paginate results by page, use the following parameters:
+
+
+
+
+```bash
+GET /api/articles?pagination[page]=1&pagination[pageSize]=10
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
pagination: {
page: 1,
@@ -250,14 +274,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/articles?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/articles?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
// ...
],
@@ -269,10 +296,13 @@ await request(\`/api/articles?\${query}\`);`
"total": 48
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Pagination by offset
@@ -291,17 +321,21 @@ The default and maximum values for `pagination[limit]` can be [configured in the
+
+
+
+
+```bash
+GET /api/articles?pagination[start]=0&pagination[limit]=10
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
pagination: {
start: 0,
@@ -311,14 +345,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/articles?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/articles?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
// ...
],
@@ -329,7 +366,10 @@ await request(\`/api/articles?\${query}\`);`
"total": 42
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
From 3db3c356c3551e4642b91d997063c3222dd4a538 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 17:43:04 +0200
Subject: [PATCH 18/55] Migrate REST locale and publicationFilter pages to
standard code blocks
Convert the Endpoint blocks on the REST locale and publicationFilter pages to the new authoring format (fenced code + Responses).
---
docusaurus/docs/cms/api/rest/locale.md | 526 +++++++--------
.../docs/cms/api/rest/publication-filter.md | 616 +++++++++++-------
2 files changed, 635 insertions(+), 507 deletions(-)
diff --git a/docusaurus/docs/cms/api/rest/locale.md b/docusaurus/docs/cms/api/rest/locale.md
index 4db4189937..468a51a134 100644
--- a/docusaurus/docs/cms/api/rest/locale.md
+++ b/docusaurus/docs/cms/api/rest/locale.md
@@ -75,52 +75,54 @@ The following table lists the new possible use cases added by i18n to the REST A
method="GET"
path="/api/restaurants?locale=fr"
title="Get all documents in a specific locale"
- description="Returns all documents for a given locale."
- codeTabs={[
- {
- label: 'Request',
- code: `GET http://localhost:1337/api/restaurants?locale=fr`,
- },
- ]}
- responses={[
+ description="Returns all documents for a given locale.">
+
+```bash
+GET http://localhost:1337/api/restaurants?locale=fr
+```
+
+
+
+
+```json
+{
+ "data": [
{
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: [
- {
- id: 5,
- documentId: "h90lgohlzfpjf3bvan72mzll",
- Title: "Meilleures pizzas",
- Body: [
- {
- type: "paragraph",
- children: [
- {
- type: "text",
- text: "On déguste les meilleures pizzas de la ville à la Pizzeria Arrivederci."
- }
- ]
- }
- ],
- createdAt: "2024-03-06T22:08:59.643Z",
- updatedAt: "2024-03-06T22:10:21.127Z",
- publishedAt: "2024-03-06T22:10:21.130Z",
- locale: "fr"
- }
- ],
- meta: {
- pagination: {
- page: 1,
- pageSize: 25,
- pageCount: 1,
- total: 1
- }
+ "id": 5,
+ "documentId": "h90lgohlzfpjf3bvan72mzll",
+ "Title": "Meilleures pizzas",
+ "Body": [
+ {
+ "type": "paragraph",
+ "children": [
+ {
+ "type": "text",
+ "text": "On déguste les meilleures pizzas de la ville à la Pizzeria Arrivederci."
+ }
+ ]
}
- }, null, 2),
- },
- ]}
-/>
+ ],
+ "createdAt": "2024-03-06T22:08:59.643Z",
+ "updatedAt": "2024-03-06T22:10:21.127Z",
+ "publishedAt": "2024-03-06T22:10:21.130Z",
+ "locale": "fr"
+ }
+ ],
+ "meta": {
+ "pagination": {
+ "page": 1,
+ "pageSize": 25,
+ "pageCount": 1,
+ "total": 1
+ }
+ }
+}
+```
+
+
+
+
+
### `GET` Get a document in a specific locale {#rest-get}
@@ -140,49 +142,51 @@ To get a specific document in a collection type in a given locale, add the `loca
method="GET"
path="/api/restaurants/:documentId?locale=fr"
title="Get a document in a specific locale (collection type)"
- description="Returns a specific document in a collection type for a given locale."
- codeTabs={[
- {
- label: 'Request',
- code: `GET /api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr`,
- },
- ]}
- responses={[
+ description="Returns a specific document in a collection type for a given locale.">
+
+```bash
+GET /api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr
+```
+
+
+
+
+```json
+{
+ "data": [
{
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: [
- {
- id: 22,
- documentId: "lr5wju2og49bf820kj9kz8c3",
- Name: "Biscotte Restaurant",
- Description: [
- {
- type: "paragraph",
- children: [
- {
- type: "text",
- text: "Bienvenue au restaurant Biscotte! Le Restaurant Biscotte propose une cuisine à base de produits frais et de qualité, souvent locaux, biologiques lorsque cela est possible, et toujours produits par des producteurs passionnés."
- }
- ]
- }
- ],
- locale: "fr"
- }
- ],
- meta: {
- pagination: {
- page: 1,
- pageSize: 25,
- pageCount: 1,
- total: 3
- }
+ "id": 22,
+ "documentId": "lr5wju2og49bf820kj9kz8c3",
+ "Name": "Biscotte Restaurant",
+ "Description": [
+ {
+ "type": "paragraph",
+ "children": [
+ {
+ "type": "text",
+ "text": "Bienvenue au restaurant Biscotte! Le Restaurant Biscotte propose une cuisine à base de produits frais et de qualité, souvent locaux, biologiques lorsque cela est possible, et toujours produits par des producteurs passionnés."
+ }
+ ]
}
- }, null, 2),
- },
- ]}
-/>
+ ],
+ "locale": "fr"
+ }
+ ],
+ "meta": {
+ "pagination": {
+ "page": 1,
+ "pageSize": 25,
+ "pageCount": 1,
+ "total": 3
+ }
+ }
+}
+```
+
+
+
+
+
#### Single types {#get-one-single-type}
@@ -193,33 +197,35 @@ To get a specific single type document in a given locale, add the `locale` param
method="GET"
path="/api/homepage?locale=fr"
title="Get a document in a specific locale (single type)"
- description="Returns a specific single type document for a given locale."
- codeTabs={[
- {
- label: 'Request',
- code: `GET /api/homepage?locale=fr`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: {
- id: 10,
- documentId: "ukbpbnu8kbutpn98rsanyi50",
- Title: "Page d'accueil",
- Body: null,
- createdAt: "2024-03-07T13:28:26.349Z",
- updatedAt: "2024-03-07T13:28:26.349Z",
- publishedAt: "2024-03-07T13:28:26.353Z",
- locale: "fr"
- },
- meta: {}
- }, null, 2),
- },
- ]}
-/>
+ description="Returns a specific single type document for a given locale.">
+
+```bash
+GET /api/homepage?locale=fr
+```
+
+
+
+
+```json
+{
+ "data": {
+ "id": 10,
+ "documentId": "ukbpbnu8kbutpn98rsanyi50",
+ "Title": "Page d'accueil",
+ "Body": null,
+ "createdAt": "2024-03-07T13:28:26.349Z",
+ "updatedAt": "2024-03-07T13:28:26.349Z",
+ "publishedAt": "2024-03-07T13:28:26.353Z",
+ "locale": "fr"
+ },
+ "meta": {}
+}
+```
+
+
+
+
+
### `POST` Create a new localized document for a collection type {#rest-create}
@@ -239,39 +245,41 @@ If no locale has been passed in the request body, the document is created using
method="POST"
path="/api/restaurants"
title="Create a document for the default locale"
- description="Creates a new document using the default locale."
- codeTabs={[
- {
- label: 'Request',
- code: `POST http://localhost:1337/api/restaurants
+ description="Creates a new document using the default locale.">
+
+```bash
+POST http://localhost:1337/api/restaurants
{
"data": {
"Name": "Oplato"
}
-}`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: {
- id: 13,
- documentId: "jae8klabhuucbkgfe2xxc5dj",
- Name: "Oplato",
- Description: null,
- createdAt: "2024-03-06T22:19:54.646Z",
- updatedAt: "2024-03-06T22:19:54.646Z",
- publishedAt: "2024-03-06T22:19:54.649Z",
- locale: "en"
- },
- meta: {}
- }, null, 2),
- },
- ]}
-/>
+}
+```
+
+
+
+
+```json
+{
+ "data": {
+ "id": 13,
+ "documentId": "jae8klabhuucbkgfe2xxc5dj",
+ "Name": "Oplato",
+ "Description": null,
+ "createdAt": "2024-03-06T22:19:54.646Z",
+ "updatedAt": "2024-03-06T22:19:54.646Z",
+ "publishedAt": "2024-03-06T22:19:54.649Z",
+ "locale": "en"
+ },
+ "meta": {}
+}
+```
+
+
+
+
+
#### For a specific locale {#rest-create-specific-locale}
@@ -282,39 +290,41 @@ To create a localized entry for a locale different from the default one, add the
method="POST"
path="/api/restaurants?locale=fr"
title="Create a document for a specific locale"
- description="Creates a new document for a specified locale."
- codeTabs={[
- {
- label: 'Request',
- code: `POST http://localhost:1337/api/restaurants?locale=fr
+ description="Creates a new document for a specified locale.">
+
+```bash
+POST http://localhost:1337/api/restaurants?locale=fr
{
"data": {
"Name": "She's Cake"
}
-}`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: {
- id: 15,
- documentId: "ldcmn698iams5nuaehj69j5o",
- Name: "She's Cake",
- Description: null,
- createdAt: "2024-03-06T22:21:18.373Z",
- updatedAt: "2024-03-06T22:21:18.373Z",
- publishedAt: "2024-03-06T22:21:18.378Z",
- locale: "fr"
- },
- meta: {}
- }, null, 2),
- },
- ]}
-/>
+}
+```
+
+
+
+
+```json
+{
+ "data": {
+ "id": 15,
+ "documentId": "ldcmn698iams5nuaehj69j5o",
+ "Name": "She's Cake",
+ "Description": null,
+ "createdAt": "2024-03-06T22:21:18.373Z",
+ "updatedAt": "2024-03-06T22:21:18.373Z",
+ "publishedAt": "2024-03-06T22:21:18.378Z",
+ "locale": "fr"
+ },
+ "meta": {}
+}
+```
+
+
+
+
+
### `PUT` Create a new, or update an existing, locale version for an existing document {#rest-update}
@@ -351,39 +361,41 @@ To create a new locale for an existing document in a collection type, add the `l
method="PUT"
path="/api/restaurants/:documentId?locale=fr"
title="Create or update a locale version (collection type)"
- description="Creates a French locale for an existing restaurant, or updates it if it already exists."
- codeTabs={[
- {
- label: 'Request',
- code: `PUT http://localhost:1337/api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr
+ description="Creates a French locale for an existing restaurant, or updates it if it already exists.">
+
+```bash
+PUT http://localhost:1337/api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr
{
"data": {
"Name": "She's Cake in French"
}
-}`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: {
- id: 19,
- documentId: "lr5wju2og49bf820kj9kz8c3",
- Name: "She's Cake in French",
- Description: null,
- createdAt: "2024-03-07T12:13:09.551Z",
- updatedAt: "2024-03-07T12:13:09.551Z",
- publishedAt: "2024-03-07T12:13:09.554Z",
- locale: "fr"
- },
- meta: {}
- }, null, 2),
- },
- ]}
-/>
+}
+```
+
+
+
+
+```json
+{
+ "data": {
+ "id": 19,
+ "documentId": "lr5wju2og49bf820kj9kz8c3",
+ "Name": "She's Cake in French",
+ "Description": null,
+ "createdAt": "2024-03-07T12:13:09.551Z",
+ "updatedAt": "2024-03-07T12:13:09.551Z",
+ "publishedAt": "2024-03-07T12:13:09.554Z",
+ "locale": "fr"
+ },
+ "meta": {}
+}
+```
+
+
+
+
+
#### In a single type {#rest-put-single-type}
@@ -394,39 +406,41 @@ To create a new locale for an existing single type document, add the `locale` pa
method="PUT"
path="/api/homepage?locale=fr"
title="Create or update a locale version (single type)"
- description="Creates a French locale for an existing Homepage single type, or updates it if it already exists."
- codeTabs={[
- {
- label: 'Request',
- code: `PUT http://localhost:1337/api/homepage?locale=fr
+ description="Creates a French locale for an existing Homepage single type, or updates it if it already exists.">
+
+```bash
+PUT http://localhost:1337/api/homepage?locale=fr
{
"data": {
"Title": "Page d'accueil"
}
-}`,
- },
- ]}
- responses={[
- {
- status: 200,
- statusText: 'OK',
- body: JSON.stringify({
- data: {
- id: 10,
- documentId: "ukbpbnu8kbutpn98rsanyi50",
- Title: "Page d'accueil",
- Body: null,
- createdAt: "2024-03-07T13:28:26.349Z",
- updatedAt: "2024-03-07T13:28:26.349Z",
- publishedAt: "2024-03-07T13:28:26.353Z",
- locale: "fr"
- },
- meta: {}
- }, null, 2),
- },
- ]}
-/>
+}
+```
+
+
+
+
+```json
+{
+ "data": {
+ "id": 10,
+ "documentId": "ukbpbnu8kbutpn98rsanyi50",
+ "Title": "Page d'accueil",
+ "Body": null,
+ "createdAt": "2024-03-07T13:28:26.349Z",
+ "updatedAt": "2024-03-07T13:28:26.349Z",
+ "publishedAt": "2024-03-07T13:28:26.353Z",
+ "locale": "fr"
+ },
+ "meta": {}
+}
+```
+
+
+
+
+
@@ -445,21 +459,23 @@ To delete only a specific locale version of a document in a collection type, add
method="DELETE"
path="/api/restaurants/:documentId?locale=fr"
title="Delete a locale version (collection type)"
- description="Deletes a specific locale version of a document in a collection type."
- codeTabs={[
- {
- label: 'Request',
- code: `DELETE /api/restaurants/abcdefghijklmno456?locale=fr`,
- },
- ]}
- responses={[
- {
- status: 204,
- statusText: 'No Content',
- body: '',
- },
- ]}
-/>
+ description="Deletes a specific locale version of a document in a collection type.">
+
+```bash
+DELETE /api/restaurants/abcdefghijklmno456?locale=fr
+```
+
+
+
+
+```json
+
+```
+
+
+
+
+
#### In a single type {#rest-delete-single-type}
@@ -470,18 +486,20 @@ To delete only a specific locale version of a single type document, add the `loc
method="DELETE"
path="/api/homepage?locale=fr"
title="Delete a locale version (single type)"
- description="Deletes a specific locale version of a single type document."
- codeTabs={[
- {
- label: 'Request',
- code: `DELETE /api/homepage?locale=fr`,
- },
- ]}
- responses={[
- {
- status: 204,
- statusText: 'No Content',
- body: '',
- },
- ]}
-/>
+ description="Deletes a specific locale version of a single type document.">
+
+```bash
+DELETE /api/homepage?locale=fr
+```
+
+
+
+
+```json
+
+```
+
+
+
+
+
diff --git a/docusaurus/docs/cms/api/rest/publication-filter.md b/docusaurus/docs/cms/api/rest/publication-filter.md
index b4e9506fa6..c9bdc8860b 100644
--- a/docusaurus/docs/cms/api/rest/publication-filter.md
+++ b/docusaurus/docs/cms/api/rest/publication-filter.md
@@ -90,18 +90,22 @@ This parameter combination works only on a given locale; to find these documents
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return the drafts that have never been published for their locale.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=never-published' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
status: 'draft',
publicationFilter: 'never-published',
@@ -109,14 +113,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "a1b2c3d4e5f6g7h8i9j0klm",
@@ -133,10 +140,13 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Find drafts never published in any locale {#never-published-document}
@@ -147,18 +157,22 @@ A document counts as published as soon as one of its locales is published: the d
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return the drafts of documents never published in any locale.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=never-published-document' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
status: 'draft',
publicationFilter: 'never-published-document',
@@ -166,14 +180,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "d41r46wac4xix5vpba7561at",
@@ -190,10 +207,13 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Find modified documents {#modified}
@@ -204,18 +224,22 @@ For instance, with `status=draft`, the query returns the draft versions:
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return the draft versions of documents with unpublished changes.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=modified' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
status: 'draft',
publicationFilter: 'modified',
@@ -223,14 +247,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "a1b2c3d4e5f6g7h8i9j0klm",
@@ -247,10 +274,13 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
With `status=published` (the REST default), the same query returns the currently live version of those documents instead:
@@ -258,32 +288,39 @@ With `status=published` (the REST default), the same query returns the currently
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return the currently live versions of documents with unpublished changes.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?publicationFilter=modified' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
publicationFilter: 'modified',
}, {
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "a1b2c3d4e5f6g7h8i9j0klm",
@@ -300,10 +337,13 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Find unmodified documents {#unmodified}
@@ -314,18 +354,22 @@ For instance, with `status=draft`, the query returns the draft versions:
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return the draft versions of documents unchanged since their last publication.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=unmodified' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
status: 'draft',
publicationFilter: 'unmodified',
@@ -333,14 +377,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "a1b2c3d4e5f6g7h8i9j0klm",
@@ -357,10 +404,13 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
With `status=published` (the REST default), the same query returns the currently live version of those documents instead:
@@ -368,32 +418,39 @@ With `status=published` (the REST default), the same query returns the currently
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return the currently live versions of documents unchanged since their last publication.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?publicationFilter=unmodified' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
publicationFilter: 'unmodified',
}, {
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "a1b2c3d4e5f6g7h8i9j0klm",
@@ -410,10 +467,13 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Find documents with a published version {#has-published-version}
@@ -424,18 +484,22 @@ For instance, with `status=draft`, the query returns the draft versions:
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return the draft versions of documents that also have a published version for the same locale.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=has-published-version' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
status: 'draft',
publicationFilter: 'has-published-version',
@@ -443,14 +507,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "a1b2c3d4e5f6g7h8i9j0klm",
@@ -467,10 +534,13 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
With `status=published` (the REST default), the same query returns the currently live version of those documents instead:
@@ -478,32 +548,39 @@ With `status=published` (the REST default), the same query returns the currently
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return the currently live versions of documents that also have a published version for the same locale.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?publicationFilter=has-published-version' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
publicationFilter: 'has-published-version',
}, {
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "a1b2c3d4e5f6g7h8i9j0klm",
@@ -520,10 +597,13 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Find documents with a published version in at least one locale {#has-published-version-document}
@@ -532,18 +612,22 @@ await request(\`/api/restaurants?\${query}\`);`
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return the draft versions of documents published in at least one locale.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?status=draft&publicationFilter=has-published-version-document' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
status: 'draft',
publicationFilter: 'has-published-version-document',
@@ -551,14 +635,17 @@ const query = qs.stringify({
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "a1b2c3d4e5f6g7h8i9j0klm",
@@ -575,10 +662,13 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
## Diagnostic values {#diagnostics}
@@ -592,32 +682,39 @@ The `published-without-draft` and `published-with-draft` values are meant for da
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return published documents with no matching draft version for the same locale.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?publicationFilter=published-without-draft' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
publicationFilter: 'published-without-draft',
}, {
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "j0klm1n2o3p4q5r6s7t8u9v",
@@ -634,42 +731,52 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
`publicationFilter=published-with-draft` selects published documents that also have a draft, which is every published document in a healthy database:
'`
- },
- {
- label: "JavaScript",
- code: `const qs = require('qs');
+ description="Return published documents that also have a matching draft version for the same locale.">
+
+
+
+
+```bash
+curl 'http://localhost:1337/api/restaurants?publicationFilter=published-with-draft' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const qs = require('qs');
const query = qs.stringify({
publicationFilter: 'published-with-draft',
}, {
encodeValuesOnly: true, // prettify URL
});
-await request(\`/api/restaurants?\${query}\`);`
- }
- ]}
- responses={[
- {
- status: 200,
- statusText: "OK",
- body: `{
+await request(`/api/restaurants?${query}`);
+```
+
+
+
+
+
+
+
+```json
+{
"data": [
{
"documentId": "a1b2c3d4e5f6g7h8i9j0klm",
@@ -686,10 +793,13 @@ await request(\`/api/restaurants?\${query}\`);`
"total": 1
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
From b64bc6bd4882b4d1df99b29746bf029201bfce56 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 17:44:42 +0200
Subject: [PATCH 19/55] Migrate REST understanding-populate guide to standard
code blocks
Convert the active Endpoint blocks on the understanding populate guide to the new authoring format (fenced code + Responses). Commented-out blocks are left untouched.
---
.../api/rest/guides/understanding-populate.md | 333 +++++++++---------
1 file changed, 171 insertions(+), 162 deletions(-)
diff --git a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md
index 0792aa1229..268a964c06 100644
--- a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md
+++ b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md
@@ -85,23 +85,21 @@ The following example is the full response for all 4 entries from the `articles`
Notice how the response only includes the `title`, `slug`, `createdAt`, `updatedAt`, `publishedAt`, and `locale` fields, and the field content of the article as handled by the CKEditor plugin (`ckeditor_content`, truncated for brevity):
+
+```bash
+GET /api/articles
+```
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -156,10 +154,13 @@ Notice how the response only includes the `title`, `slug`, `createdAt`, `updated
"total": 4
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Example: With `populate=*`
@@ -180,23 +181,21 @@ To populate deeply nested components, see the [populate components](#populate-co
+
+```bash
+GET /api/articles?populate=*
+```
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -338,10 +337,13 @@ To populate deeply nested components, see the [populate components](#populate-co
"total": 4
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
## Populate specific relations and fields
@@ -429,23 +431,21 @@ Notice that the response does not include any media fields, relations, component
+
+```bash
+GET /api/articles
+```
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -500,10 +500,13 @@ Notice that the response does not include any media fields, relations, component
"total": 4
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
#### Example: With `populate[0]=category`
@@ -514,23 +517,21 @@ The following example is the full response for all 4 entries from the `articles`
Notice that the response now includes additional data with the `category` field for each article (see highlighted lines):
+
+```bash
+GET /api/articles?populate[0]=category
+```
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -624,10 +625,13 @@ Notice that the response now includes additional data with the `category` field
"total": 4
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Populate several levels deep for specific relations
@@ -670,23 +674,21 @@ Let's compare and explain the responses returned with `populate[0]=category` (1
When we only populate 1 level deep, asking for the categories associated to articles, we can get the following example response (highlighted lines show the `category` relations field):
+
+```bash
+GET /api/articles?populate[0]=category
+```
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -780,10 +782,13 @@ When we only populate 1 level deep, asking for the categories associated to arti
"total": 4
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
#### Example: With 2-level deep population
@@ -792,23 +797,21 @@ When we populate 2 levels deep, asking for the categories associated to articles
Notice that we now have the `restaurants` relation field included with the response inside the `category` relation (see highlighted lines):
+
+```bash
+GET /api/articles?populate[category][populate][0]=restaurants
+```
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -886,10 +889,13 @@ Notice that we now have the `restaurants` relation field included with the respo
"total": 4
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Populate components
@@ -933,23 +939,21 @@ When we only populate the `seo` component, we go only 1 level deep, and we can g
Notice there's no mention of the `metaSocial` component nested within the `seo` component:
+
+```bash
+GET /api/articles?populate[0]=seo
+```
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -994,10 +998,13 @@ Notice there's no mention of the `metaSocial` component nested within the `seo`
"total": 4
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
#### Example: 1st level and 2nd level component
@@ -1006,23 +1013,21 @@ When we populate 2 levels deep, asking both for the `seo` component and the `met
Notice that we now have the `metaSocial` component-related data included with the response (see highlighted lines):
+
+```bash
+GET /api/articles?populate[0]=seo&populate[1]=seo.metaSocial
+```
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -1076,10 +1081,13 @@ Notice that we now have the `metaSocial` component-related data included with th
"total": 4
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
### Populate dynamic zones
@@ -1363,23 +1371,21 @@ In the following example response, highlighted lines show that:
- But because we have only asked to populate everything for the `CtaCommandLine` component and have not defined anything for the `faq` component, no data from the `faq` component is returned.
+
+```bash
+GET /api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=*
+```
+
+
+
+
+```json
+{
"data": [
{
"id": 1,
@@ -1483,10 +1489,13 @@ In the following example response, highlighted lines show that:
"total": 4
}
}
-}`
- }
- ]}
-/>
+}
+```
+
+
+
+
+
:::tip Avoid over-populating in production
Using `populate=*` or deep population plugins can create unpredictable, costly database queries. In production, always populate explicitly and limit depth to 2-3 levels. Consider using route-level middlewares to centralize population logic. See on the Strapi blog.
From 2bf7d702cadc8cb530bed5ac9c86668ee5c2cd11 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 17:52:25 +0200
Subject: [PATCH 20/55] Restore collapsible long responses using
ExpandableContent
Add a collapsible prop to ResponseTab that wraps its content in the existing ExpandableContent component (Show more / Show less), and mark the long responses on the understanding-populate guide as collapsible, restoring the behavior lost when the Endpoint component was reworked.
---
.../cms/api/rest/guides/understanding-populate.md | 14 +++++++-------
.../src/components/ApiReference/Responses.jsx | 9 +++++++--
2 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md
index 268a964c06..ba3749370a 100644
--- a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md
+++ b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md
@@ -192,7 +192,7 @@ GET /api/articles?populate=*
```
-
+
```json
{
@@ -528,7 +528,7 @@ GET /api/articles?populate[0]=category
```
-
+
```json
{
@@ -685,7 +685,7 @@ GET /api/articles?populate[0]=category
```
-
+
```json
{
@@ -808,7 +808,7 @@ GET /api/articles?populate[category][populate][0]=restaurants
```
-
+
```json
{
@@ -950,7 +950,7 @@ GET /api/articles?populate[0]=seo
```
-
+
```json
{
@@ -1024,7 +1024,7 @@ GET /api/articles?populate[0]=seo&populate[1]=seo.metaSocial
```
-
+
```json
{
@@ -1382,7 +1382,7 @@ GET /api/articles?populate[blocks][on][blocks.related-articles][populate][articl
```
-
+
```json
{
diff --git a/docusaurus/src/components/ApiReference/Responses.jsx b/docusaurus/src/components/ApiReference/Responses.jsx
index ab262cabb9..bf118f88b6 100644
--- a/docusaurus/src/components/ApiReference/Responses.jsx
+++ b/docusaurus/src/components/ApiReference/Responses.jsx
@@ -2,6 +2,7 @@ import React, { Children, isValidElement } from 'react';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import clsx from 'clsx';
+import ExpandableContent from '../ExpandableContent';
import styles from './api-reference.module.scss';
/**
@@ -23,7 +24,7 @@ function labelClass(status) {
return status < 400 ? styles['responseStatus--ok'] : styles['responseStatus--err'];
}
-export function ResponseTab({ status, statusText = '', children }) {
+export function ResponseTab({ status, statusText = '', collapsible = false, children }) {
const s = Number(status);
return (
<>
@@ -33,7 +34,11 @@ export function ResponseTab({ status, statusText = '', children }) {
{s} {statusText}
- {children}
+ {collapsible ? (
+ {children}
+ ) : (
+ children
+ )}
>
);
}
From 35358b5bb6263b68e607aa878b20f5b8031dfe1b Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 18:06:40 +0200
Subject: [PATCH 21/55] Align terminal Ask AI button color and nudge param
descriptions
Give the terminal Ask AI button the same icon/label color and rest opacity as the copy/wrap buttons so all three match before hover. Add a 6px top padding to parameter descriptions so they line up with the required/optional badge on the same row.
---
.../ApiReference/api-reference.module.scss | 3 ++
docusaurus/src/scss/code-block.scss | 28 ++++++-------------
2 files changed, 12 insertions(+), 19 deletions(-)
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index 2023d183f7..d35cf8dfd4 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -382,6 +382,9 @@
font-size: 13px;
line-height: 1.5;
color: var(--strapi-fg-3);
+ // Nudge down to visually align the description text with the
+ // required/optional badge on the same row.
+ padding-top: 6px;
code {
font-family: var(--strapi-font-family-mono);
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 4f4ebd1952..9767d99a3a 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -273,33 +273,23 @@ pre.prism-code {
background: var(--strapi-neutral-0) !important;
border: 1px solid var(--strapi-neutral-200) !important;
- // Dimmed at rest (like the copy/wrap icons), full opacity on hover.
- // !important beats the legacy .clean-btn opacity:1 rules (this button also
- // carries the clean-btn class).
- i {
- font-size: 12px;
- color: var(--strapi-primary-500);
+ // Same color + opacity as the copy/wrap buttons (which use --strapi-fg-1
+ // at 0.6 opacity), so all three action buttons match at rest. !important
+ // beats the legacy .clean-btn rules (this button also carries clean-btn).
+ i, span {
+ color: var(--strapi-fg-1) !important;
opacity: 0.6 !important;
}
- span {
- color: var(--strapi-fg-1);
- opacity: 0.6 !important;
+ i {
+ font-size: 12px;
}
- // On hover only darken the label + icon and bring them to full opacity;
- // keep background and border as-is. The button also carries the `clean-btn`
- // class, whose legacy :hover would otherwise tint the background grey.
+ // On hover: full opacity, matching the copy/wrap icons.
&:hover {
background: var(--strapi-neutral-0) !important;
- i {
- color: var(--strapi-primary-700) !important;
- opacity: 1 !important;
- }
-
- span {
- color: var(--strapi-neutral-800) !important;
+ i, span {
opacity: 1 !important;
}
}
From bf6173dea5a01e3a4577d10ef1cc11bc402320dc Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 18:07:58 +0200
Subject: [PATCH 22/55] Remove top margin above parameter types
Drop the 2px top margin on parameter type labels so the type sits directly under the parameter name in REST API parameter tables.
---
docusaurus/src/components/ApiReference/api-reference.module.scss | 1 -
1 file changed, 1 deletion(-)
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index d35cf8dfd4..b1923e4d96 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -356,7 +356,6 @@
font-family: var(--strapi-font-family-mono);
font-size: 11px;
color: var(--strapi-fg-4);
- margin-top: 2px;
}
&__badge {
From 38a5d1f93e5aef92b2ff966fe765d227b993d8f0 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Mon, 20 Jul 2026 18:20:45 +0200
Subject: [PATCH 23/55] Remove blinking cursor from terminal code blocks
Stop injecting the end-of-line blinking cursor in terminal code blocks; the wrapper ref now only relocates the action buttons into the title bar.
---
docusaurus/src/theme/CodeBlock/index.js | 35 +++----------------------
1 file changed, 3 insertions(+), 32 deletions(-)
diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js
index cb68422675..b4bb56d5e2 100644
--- a/docusaurus/src/theme/CodeBlock/index.js
+++ b/docusaurus/src/theme/CodeBlock/index.js
@@ -155,41 +155,12 @@ export default function CodeBlockWrapper(props) {
requestAnimationFrame(() => requestAnimationFrame(move));
}, []);
+ // Ref callback for the terminal wrapper. Only relocates the action buttons
+ // into the title bar; the blinking end-of-line cursor was removed.
const injectCursor = useCallback((node) => {
terminalRef.current = node;
if (node) relocateButtons(node);
- if (!node) return;
-
- // Find the last token line and append a real cursor span
- const injectCursorElement = () => {
- // Remove any previously injected cursor
- const existing = node.querySelector('.terminal-cursor');
- if (existing) existing.remove();
-
- const codeEl = node.querySelector('code');
- if (!codeEl) return;
-
- const lastLine = codeEl.querySelector('.token-line:last-child');
- if (!lastLine) return;
-
- const cursor = document.createElement('span');
- cursor.className = 'terminal-cursor';
-
- // Insert before the trailing so the cursor stays on the same line
- const lastBr = lastLine.querySelector('br:last-child');
- if (lastBr) {
- lastLine.insertBefore(cursor, lastBr);
- lastBr.remove();
- } else {
- lastLine.appendChild(cursor);
- }
- };
-
- // Run after Docusaurus finishes rendering the code block
- requestAnimationFrame(() => {
- requestAnimationFrame(injectCursorElement);
- });
- }, []);
+ }, [relocateButtons]);
// Terminal blocks: macOS-style wrapper with title bar + blinking cursor
if (isTerminal) {
From a18b12ff90820e44367ff47ccdd5f531b36c8450 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 10:53:07 +0200
Subject: [PATCH 24/55] Use real cURL commands in REST API request examples
Replace raw URL/HTTP request snippets (GET /api/..., POST http://...) under the cURL tabs with real curl commands including the Authorization header, and -X/-H/-d for POST/PUT/DELETE, matching the main REST reference page.
---
docusaurus/docs/cms/api/rest/filters.md | 20 +++--
docusaurus/docs/cms/api/rest/locale.md | 81 +++++++++++--------
.../docs/cms/api/rest/populate-select.md | 15 ++--
.../docs/cms/api/rest/sort-pagination.md | 20 +++--
4 files changed, 81 insertions(+), 55 deletions(-)
diff --git a/docusaurus/docs/cms/api/rest/filters.md b/docusaurus/docs/cms/api/rest/filters.md
index 22bf630cc2..bd25a57928 100644
--- a/docusaurus/docs/cms/api/rest/filters.md
+++ b/docusaurus/docs/cms/api/rest/filters.md
@@ -94,10 +94,11 @@ By default, the filters can only be used from `find` endpoints generated by the
description="Use the $eq filter operator to find an exact match.">
-
+
```bash
-GET /api/users?filters[username][$eq]=John
+curl 'http://localhost:1337/api/users?filters[username][$eq]=John' \
+ -H 'Authorization: Bearer '
```
@@ -165,10 +166,11 @@ await request(`/api/users?${query}`);
description="Use the $in filter operator with an array of values to find multiple exact values.">
-
+
```bash
-GET /api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8
+curl 'http://localhost:1337/api/restaurants?filters[id][$in][0]=3&filters[id][$in][1]=6&filters[id][$in][2]=8' \
+ -H 'Authorization: Bearer '
```
@@ -232,10 +234,11 @@ await request(`/api/restaurants?${query}`);
description="Combine $and and $or operators for complex filtering.">
-
+
```bash
-GET /api/books?filters[$and][0][$or][0][date][$eq]=2020-01-01&filters[$and][0][$or][1][date][$eq]=2020-01-02&filters[$and][1][author][name][$eq]=Kai%20doe
+curl 'http://localhost:1337/api/books?filters[$and][0][$or][0][date][$eq]=2020-01-01&filters[$and][0][$or][1][date][$eq]=2020-01-02&filters[$and][1][author][name][$eq]=Kai%20doe' \
+ -H 'Authorization: Bearer '
```
@@ -331,10 +334,11 @@ Querying your API with deep filters may cause performance issues. If one of you
description="Use deep filtering to filter on a relation's fields.">
-
+
```bash
-GET /api/restaurants?filters[chef][restaurants][stars][$eq]=5
+curl 'http://localhost:1337/api/restaurants?filters[chef][restaurants][stars][$eq]=5' \
+ -H 'Authorization: Bearer '
```
diff --git a/docusaurus/docs/cms/api/rest/locale.md b/docusaurus/docs/cms/api/rest/locale.md
index 468a51a134..5b66b74e62 100644
--- a/docusaurus/docs/cms/api/rest/locale.md
+++ b/docusaurus/docs/cms/api/rest/locale.md
@@ -78,7 +78,8 @@ The following table lists the new possible use cases added by i18n to the REST A
description="Returns all documents for a given locale.">
```bash
-GET http://localhost:1337/api/restaurants?locale=fr
+curl 'http://localhost:1337/api/restaurants?locale=fr' \
+ -H 'Authorization: Bearer '
```
@@ -145,7 +146,8 @@ To get a specific document in a collection type in a given locale, add the `loca
description="Returns a specific document in a collection type for a given locale.">
```bash
-GET /api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr
+curl 'http://localhost:1337/api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr' \
+ -H 'Authorization: Bearer '
```
@@ -200,7 +202,8 @@ To get a specific single type document in a given locale, add the `locale` param
description="Returns a specific single type document for a given locale.">
```bash
-GET /api/homepage?locale=fr
+curl 'http://localhost:1337/api/homepage?locale=fr' \
+ -H 'Authorization: Bearer '
```
@@ -248,13 +251,15 @@ If no locale has been passed in the request body, the document is created using
description="Creates a new document using the default locale.">
```bash
-POST http://localhost:1337/api/restaurants
-
-{
- "data": {
- "Name": "Oplato"
- }
-}
+curl -X POST \
+ 'http://localhost:1337/api/restaurants' \
+ -H 'Authorization: Bearer ' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "data": {
+ "Name": "Oplato"
+ }
+ }'
```
@@ -293,13 +298,15 @@ To create a localized entry for a locale different from the default one, add the
description="Creates a new document for a specified locale.">
```bash
-POST http://localhost:1337/api/restaurants?locale=fr
-
-{
- "data": {
- "Name": "She's Cake"
- }
-}
+curl -X POST \
+ 'http://localhost:1337/api/restaurants?locale=fr' \
+ -H 'Authorization: Bearer ' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "data": {
+ "Name": "She'\''s Cake"
+ }
+ }'
```
@@ -364,13 +371,15 @@ To create a new locale for an existing document in a collection type, add the `l
description="Creates a French locale for an existing restaurant, or updates it if it already exists.">
```bash
-PUT http://localhost:1337/api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr
-
-{
- "data": {
- "Name": "She's Cake in French"
- }
-}
+curl -X PUT \
+ 'http://localhost:1337/api/restaurants/lr5wju2og49bf820kj9kz8c3?locale=fr' \
+ -H 'Authorization: Bearer ' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "data": {
+ "Name": "She'\''s Cake in French"
+ }
+ }'
```
@@ -409,13 +418,15 @@ To create a new locale for an existing single type document, add the `locale` pa
description="Creates a French locale for an existing Homepage single type, or updates it if it already exists.">
```bash
-PUT http://localhost:1337/api/homepage?locale=fr
-
-{
- "data": {
- "Title": "Page d'accueil"
- }
-}
+curl -X PUT \
+ 'http://localhost:1337/api/homepage?locale=fr' \
+ -H 'Authorization: Bearer ' \
+ -H 'Content-Type: application/json' \
+ -d '{
+ "data": {
+ "Title": "Page d'\''accueil"
+ }
+ }'
```
@@ -462,7 +473,9 @@ To delete only a specific locale version of a document in a collection type, add
description="Deletes a specific locale version of a document in a collection type.">
```bash
-DELETE /api/restaurants/abcdefghijklmno456?locale=fr
+curl -X DELETE \
+ 'http://localhost:1337/api/restaurants/abcdefghijklmno456?locale=fr' \
+ -H 'Authorization: Bearer '
```
@@ -489,7 +502,9 @@ To delete only a specific locale version of a single type document, add the `loc
description="Deletes a specific locale version of a single type document.">
```bash
-DELETE /api/homepage?locale=fr
+curl -X DELETE \
+ 'http://localhost:1337/api/homepage?locale=fr' \
+ -H 'Authorization: Bearer '
```
diff --git a/docusaurus/docs/cms/api/rest/populate-select.md b/docusaurus/docs/cms/api/rest/populate-select.md
index 89be62c3c6..a754c15b0f 100644
--- a/docusaurus/docs/cms/api/rest/populate-select.md
+++ b/docusaurus/docs/cms/api/rest/populate-select.md
@@ -58,10 +58,11 @@ Field selection does not work on relational, media, component, or dynamic zone f
description="Use the fields parameter to select only specific fields in the response.">
-
+
```bash
-GET /api/restaurants?fields[0]=name&fields[1]=description
+curl 'http://localhost:1337/api/restaurants?fields[0]=name&fields[1]=description' \
+ -H 'Authorization: Bearer '
```
@@ -177,10 +178,11 @@ Top-level pagination parameters (e.g., `pagination[page]` and `pagination[pageSi
description="Combine fields and populate parameters to select specific fields on both the main entry and its relations.">
-
+
```bash
-GET /api/articles?fields[0]=title&fields[1]=slug&populate[headerImage][fields][0]=name&populate[headerImage][fields][1]=url
+curl 'http://localhost:1337/api/articles?fields[0]=title&fields[1]=slug&populate[headerImage][fields][0]=name&populate[headerImage][fields][1]=url' \
+ -H 'Authorization: Bearer '
```
@@ -247,10 +249,11 @@ await request(`/api/articles?${query}`);
description="Combine populate with sort and filter parameters to refine which related entries are returned.">
-
+
```bash
-GET /api/articles?populate[categories][sort][0]=name%3Aasc&populate[categories][filters][name][$eq]=Cars
+curl 'http://localhost:1337/api/articles?populate[categories][sort][0]=name%3Aasc&populate[categories][filters][name][$eq]=Cars' \
+ -H 'Authorization: Bearer '
```
diff --git a/docusaurus/docs/cms/api/rest/sort-pagination.md b/docusaurus/docs/cms/api/rest/sort-pagination.md
index 4cc0ee1c99..2e51a6b42f 100644
--- a/docusaurus/docs/cms/api/rest/sort-pagination.md
+++ b/docusaurus/docs/cms/api/rest/sort-pagination.md
@@ -62,10 +62,11 @@ You can sort by multiple fields by passing fields in a `sort` array.
description="Sort results by Description and Name fields.">
-
+
```bash
-GET /api/restaurants?sort[0]=Description&sort[1]=Name
+curl 'http://localhost:1337/api/restaurants?sort[0]=Description&sort[1]=Name' \
+ -H 'Authorization: Bearer '
```
@@ -150,10 +151,11 @@ Using the `sort` parameter and defining `:asc` or `:desc` on sorted fields, you
description="Sort results by Description ascending and Name descending.">
-
+
```bash
-GET /api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc
+curl 'http://localhost:1337/api/restaurants?sort[0]=Description:asc&sort[1]=Name:desc' \
+ -H 'Authorization: Bearer '
```
@@ -254,10 +256,11 @@ To paginate results by page, use the following parameters:
description="Return only 10 entries on page 1.">
-
+
```bash
-GET /api/articles?pagination[page]=1&pagination[pageSize]=10
+curl 'http://localhost:1337/api/articles?pagination[page]=1&pagination[pageSize]=10' \
+ -H 'Authorization: Bearer '
```
@@ -325,10 +328,11 @@ The default and maximum values for `pagination[limit]` can be [configured in the
description="Return only the first 10 entries using offset.">
-
+
```bash
-GET /api/articles?pagination[start]=0&pagination[limit]=10
+curl 'http://localhost:1337/api/articles?pagination[start]=0&pagination[limit]=10' \
+ -H 'Authorization: Bearer '
```
From 24a43f37a2fc22bc63b58d0adb86f62dd71e664c Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 11:25:39 +0200
Subject: [PATCH 25/55] Remove empty gap above code in terminal blocks on
mobile
On mobile, code blocks add a 48px top padding to clear the always-visible floating action buttons. Terminal blocks keep their buttons in the title bar, so that padding left a large empty gap above the code. Reset it to 0 for terminal blocks while leaving regular code blocks unchanged.
---
docusaurus/src/scss/code-block.scss | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 9767d99a3a..973c57765d 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -722,6 +722,18 @@ pre.prism-code {
padding-top: 48px;
}
}
+ }
+
+ // Terminal blocks keep their action buttons in the title bar even on mobile,
+ // so the 48px top padding (meant to clear floating buttons) just leaves a big
+ // empty gap above the code. Remove it here.
+ .code-block-enhanced .theme-code-block {
+ &[class*="codeBlockContainer"],
+ [class*="codeBlockContainer"] {
+ [class*="codeBlockContent"] {
+ padding-top: 0;
+ }
+ }
// Reset button position on mobile (don't put them in title bar)
&:has([class*="codeBlockTitle"]) {
From 44961101e93304c25d5768a66bfeaf5f66b9d74f Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 11:33:03 +0200
Subject: [PATCH 26/55] Add cURL and JavaScript tabs to understanding-populate
examples
Replace the single terminal-style request in each understanding-populate example with two tabs (cURL and JavaScript), consistent with the main REST reference page. The JavaScript tab uses fetch with the request URL directly.
---
.../api/rest/guides/understanding-populate.md | 216 +++++++++++++++++-
1 file changed, 207 insertions(+), 9 deletions(-)
diff --git a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md
index ba3749370a..07716c63d9 100644
--- a/docusaurus/docs/cms/api/rest/guides/understanding-populate.md
+++ b/docusaurus/docs/cms/api/rest/guides/understanding-populate.md
@@ -91,10 +91,32 @@ Notice how the response only includes the `title`, `slug`, `createdAt`, `updated
title="Without populate"
description="Returns only default attributes, without any media fields, relations, components, or dynamic zones.">
+
+
+
```bash
-GET /api/articles
+curl 'http://localhost:1337/api/articles' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const response = await fetch(
+ 'http://localhost:1337/api/articles',
+ {
+ headers: {
+ Authorization: 'Bearer ',
+ },
+ }
+);
+const data = await response.json();
```
+
+
+
@@ -187,10 +209,32 @@ To populate deeply nested components, see the [populate components](#populate-co
title="With populate=*"
description="Returns all media fields, first-level relations, components, and dynamic zones.">
+
+
+
```bash
-GET /api/articles?populate=*
+curl 'http://localhost:1337/api/articles?populate=*' \
+ -H 'Authorization: Bearer '
```
+
+
+
+```js
+const response = await fetch(
+ 'http://localhost:1337/api/articles?populate=*',
+ {
+ headers: {
+ Authorization: 'Bearer ',
+ },
+ }
+);
+const data = await response.json();
+```
+
+
+
+
@@ -437,10 +481,32 @@ Notice that the response does not include any media fields, relations, component
title="Without populate"
description="Returns only default attributes for all articles.">
+
+
+
```bash
-GET /api/articles
+curl 'http://localhost:1337/api/articles' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const response = await fetch(
+ 'http://localhost:1337/api/articles',
+ {
+ headers: {
+ Authorization: 'Bearer ',
+ },
+ }
+);
+const data = await response.json();
```
+
+
+
@@ -523,10 +589,32 @@ Notice that the response now includes additional data with the `category` field
title="With populate[0]=category"
description="Returns articles with their related category data populated.">
+
+
+
```bash
-GET /api/articles?populate[0]=category
+curl 'http://localhost:1337/api/articles?populate[0]=category' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const response = await fetch(
+ 'http://localhost:1337/api/articles?populate[0]=category',
+ {
+ headers: {
+ Authorization: 'Bearer ',
+ },
+ }
+);
+const data = await response.json();
```
+
+
+
@@ -680,10 +768,32 @@ When we only populate 1 level deep, asking for the categories associated to arti
title="With 1-level deep population"
description="Populates the category relation 1 level deep.">
+
+
+
```bash
-GET /api/articles?populate[0]=category
+curl 'http://localhost:1337/api/articles?populate[0]=category' \
+ -H 'Authorization: Bearer '
```
+
+
+
+```js
+const response = await fetch(
+ 'http://localhost:1337/api/articles?populate[0]=category',
+ {
+ headers: {
+ Authorization: 'Bearer ',
+ },
+ }
+);
+const data = await response.json();
+```
+
+
+
+
@@ -803,10 +913,32 @@ Notice that we now have the `restaurants` relation field included with the respo
title="With 2-level deep population"
description="Populates the category relation and the nested restaurants relation 2 levels deep.">
+
+
+
```bash
-GET /api/articles?populate[category][populate][0]=restaurants
+curl 'http://localhost:1337/api/articles?populate[category][populate][0]=restaurants' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const response = await fetch(
+ 'http://localhost:1337/api/articles?populate[category][populate][0]=restaurants',
+ {
+ headers: {
+ Authorization: 'Bearer ',
+ },
+ }
+);
+const data = await response.json();
```
+
+
+
@@ -945,10 +1077,32 @@ Notice there's no mention of the `metaSocial` component nested within the `seo`
title="Only 1st level component"
description="Populates only the seo component, 1 level deep.">
+
+
+
```bash
-GET /api/articles?populate[0]=seo
+curl 'http://localhost:1337/api/articles?populate[0]=seo' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const response = await fetch(
+ 'http://localhost:1337/api/articles?populate[0]=seo',
+ {
+ headers: {
+ Authorization: 'Bearer ',
+ },
+ }
+);
+const data = await response.json();
```
+
+
+
@@ -1019,10 +1173,32 @@ Notice that we now have the `metaSocial` component-related data included with th
title="1st level and 2nd level component"
description="Populates the seo component and the nested metaSocial component.">
+
+
+
```bash
-GET /api/articles?populate[0]=seo&populate[1]=seo.metaSocial
+curl 'http://localhost:1337/api/articles?populate[0]=seo&populate[1]=seo.metaSocial' \
+ -H 'Authorization: Bearer '
+```
+
+
+
+
+```js
+const response = await fetch(
+ 'http://localhost:1337/api/articles?populate[0]=seo&populate[1]=seo.metaSocial',
+ {
+ headers: {
+ Authorization: 'Bearer ',
+ },
+ }
+);
+const data = await response.json();
```
+
+
+
@@ -1377,10 +1553,32 @@ In the following example response, highlighted lines show that:
title="Detailed population strategy for dynamic zones"
description="Populates the blocks dynamic zone using a detailed per-component population strategy.">
+
+
+
```bash
-GET /api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=*
+curl 'http://localhost:1337/api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=*' \
+ -H 'Authorization: Bearer '
```
+
+
+
+```js
+const response = await fetch(
+ 'http://localhost:1337/api/articles?populate[blocks][on][blocks.related-articles][populate][articles][populate][0]=image&populate[blocks][on][blocks.cta-command-line][populate]=*',
+ {
+ headers: {
+ Authorization: 'Bearer ',
+ },
+ }
+);
+const data = await response.json();
+```
+
+
+
+
From 41cee798ac0f1b1041fe17330ee8ccccdebdf6a0 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 11:43:33 +0200
Subject: [PATCH 27/55] Align terminal code with the title bar left edge
Terminal code blocks indented the code far to the right (line-number padding it never uses). Remove the code's left padding and the lines container's left padding so the code lines up with the title-bar traffic-light dots.
---
docusaurus/src/scss/code-block.scss | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 973c57765d..ce5cd16338 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -382,7 +382,11 @@ pre.prism-code {
background-color: transparent !important;
code {
- padding: 16px 24px;
+ // Align the code's left edge with the title-bar content (traffic-light
+ // dots) instead of the deep default indent. The wrapper's .language-*
+ // container already provides the left margin, so the code itself only
+ // needs vertical padding + a small right pad for the scrollbar.
+ padding: 16px 24px 16px 0;
background: transparent !important;
background-color: transparent !important;
@@ -391,6 +395,12 @@ pre.prism-code {
background-color: var(--strapi-primary-500) !important;
}
}
+
+ // Remove the default 24px left padding on the lines container (meant to
+ // make room for line numbers, which terminal blocks don't show).
+ [class*="codeBlockLines"] {
+ padding-left: 0 !important;
+ }
}
}
From 79e21192d32fc2bc08bf0fa5f00d9ef97459469c Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 12:02:33 +0200
Subject: [PATCH 28/55] Fix action button position and code block spacing in
tabs
For titleless non-terminal code blocks, lift the copy/wrap/Ask AI button group into the empty space above the code (top:-32px) instead of overlapping the first lines. Remove the extra bottom margin on code blocks inside tab panels (both terminal and regular) so the vertical space above and below the code is balanced.
---
docusaurus/src/scss/code-block.scss | 7 +++++++
docusaurus/src/scss/tabs.scss | 5 ++++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index ce5cd16338..a0ae68b294 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -472,6 +472,13 @@ pre.prism-code {
padding: 0;
}
}
+
+ // No title bar to host the action buttons, so lift the button group up
+ // into the empty space above the code instead of letting it overlap the
+ // first lines. (Titled blocks are handled separately further down.)
+ [class*="buttonGroup"] {
+ top: -32px;
+ }
}
svg {
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index 317452d169..28540de4f9 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -124,6 +124,9 @@
// Remove borders from code blocks inside tabs
[class*="codeBlockContainer"]:not(:has([class*="codeBlockTitle"])) {
border: none !important;
+ // Drop the default bottom margin: it left more empty space below the
+ // code than above it, unbalancing the block inside the tab panel.
+ margin-bottom: 0 !important;
}
[class*="codeBlockContainer"]:has([class*="codeBlockTitle"]) {
@@ -146,7 +149,7 @@
}
.theme-code-block {
- margin: 0 20px 20px !important;
+ margin: 0 20px !important;
border: 1px solid var(--custom-code-block-border-color) !important;
border-top: none !important;
border-radius: 0 0 var(--strapi-radius-md) var(--strapi-radius-md) !important;
From 3d92ccfc28509790ff93e42a670f5c38fca43261 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 12:19:15 +0200
Subject: [PATCH 29/55] Scope lifted action buttons to titleless code blocks
inside tabs
The top:-32px lift for the action button group must apply only to titleless code blocks inside a tab panel (the request examples). Response blocks live outside any tab, so they keep the default top position with buttons in the block's top-right corner. Scoping the rule to tab panels fixes the response block regression without affecting other code block types.
---
docusaurus/src/scss/code-block.scss | 7 -------
docusaurus/src/scss/tabs.scss | 8 ++++++++
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index a0ae68b294..ce5cd16338 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -472,13 +472,6 @@ pre.prism-code {
padding: 0;
}
}
-
- // No title bar to host the action buttons, so lift the button group up
- // into the empty space above the code instead of letting it overlap the
- // first lines. (Titled blocks are handled separately further down.)
- [class*="buttonGroup"] {
- top: -32px;
- }
}
svg {
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index 28540de4f9..e5451996eb 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -127,6 +127,14 @@
// Drop the default bottom margin: it left more empty space below the
// code than above it, unbalancing the block inside the tab panel.
margin-bottom: 0 !important;
+
+ // A titleless code block inside a tab panel has no bar to host the
+ // action buttons, so lift the button group up into the empty space
+ // above the code instead of overlapping the first lines. Scoped to tab
+ // panels only, so response blocks (outside any tab) keep top:0.
+ [class*="buttonGroup"] {
+ top: -32px;
+ }
}
[class*="codeBlockContainer"]:has([class*="codeBlockTitle"]) {
From 114b4bdce37cc8275726f2770c5b8693738df3b3 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 12:36:00 +0200
Subject: [PATCH 30/55] Align terminal window and code, dedupe copy button
Inset the terminal window so its left border lines up with the response block's opening brace, and indent the terminal code so its first character sits under the title bar's first traffic-light dot. Also remove the duplicate copy button that React re-inserted into the code area after the button group was relocated to the title bar (a MutationObserver now drops stray groups).
---
docusaurus/src/scss/code-block.scss | 12 +++++-------
docusaurus/src/scss/tabs.scss | 14 +++++++++++---
docusaurus/src/theme/CodeBlock/index.js | 24 ++++++++++++++++++++----
3 files changed, 36 insertions(+), 14 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index ce5cd16338..54d5af34a1 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -382,10 +382,8 @@ pre.prism-code {
background-color: transparent !important;
code {
- // Align the code's left edge with the title-bar content (traffic-light
- // dots) instead of the deep default indent. The wrapper's .language-*
- // container already provides the left margin, so the code itself only
- // needs vertical padding + a small right pad for the scrollbar.
+ // Left inset is handled on the lines container below (18px); keep the
+ // code's own left padding at 0 to avoid stacking.
padding: 16px 24px 16px 0;
background: transparent !important;
background-color: transparent !important;
@@ -396,10 +394,10 @@ pre.prism-code {
}
}
- // Remove the default 24px left padding on the lines container (meant to
- // make room for line numbers, which terminal blocks don't show).
+ // The default lines-container padding (for line numbers) is replaced by
+ // an 18px inset so the code lines up under the title bar's first dot.
[class*="codeBlockLines"] {
- padding-left: 0 !important;
+ padding-left: 18px !important;
}
}
}
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index e5451996eb..494425331a 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -63,6 +63,7 @@
padding: 16px 20px;
}
+
// Remove border for nested tabs container
[role="tabpanel"] .tabs-container {
border: none;
@@ -127,6 +128,9 @@
// Drop the default bottom margin: it left more empty space below the
// code than above it, unbalancing the block inside the tab panel.
margin-bottom: 0 !important;
+ // Drop the container's own left padding; the tab panel's left padding
+ // provides the code's left inset, lining it up with the response code.
+ padding-left: 0 !important;
// A titleless code block inside a tab panel has no bar to host the
// action buttons, so lift the button group up into the empty space
@@ -137,11 +141,15 @@
}
}
+
[class*="codeBlockContainer"]:has([class*="codeBlockTitle"]) {
margin: 22px 20px;
}
- // Enhanced terminal blocks inside tabs: remove double border, add spacing
+ // Enhanced terminal blocks inside tabs: remove double border, add spacing.
+ // The tab panel adds 20px left padding; the terminal window (title bar +
+ // code) is inset another 4px via its margin so its left border sits at
+ // 24px from the code column — lined up with the response block's `{`.
.code-block-enhanced {
border: none !important;
border-radius: 0 !important;
@@ -150,14 +158,14 @@
.code-title-bar {
border-radius: 0;
- margin: 0 20px;
+ margin: 0 4px;
border: 1px solid var(--custom-code-block-border-color);
border-bottom: 1px solid var(--code-title-bar-border);
border-radius: var(--strapi-radius-md) var(--strapi-radius-md) 0 0;
}
.theme-code-block {
- margin: 0 20px !important;
+ margin: 0 4px !important;
border: 1px solid var(--custom-code-block-border-color) !important;
border-top: none !important;
border-radius: 0 0 var(--strapi-radius-md) var(--strapi-radius-md) !important;
diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js
index b4bb56d5e2..7c781b7f60 100644
--- a/docusaurus/src/theme/CodeBlock/index.js
+++ b/docusaurus/src/theme/CodeBlock/index.js
@@ -147,12 +147,28 @@ export default function CodeBlockWrapper(props) {
if (!wrapper) return;
const move = () => {
const actions = wrapper.querySelector('.code-title-bar__actions');
- const group = wrapper.querySelector('[class*="buttonGroup"]');
- if (!actions || !group) return;
- if (group.parentElement === actions) return; // already moved
- actions.appendChild(group);
+ if (!actions) return;
+ // Move the native copy/wrap group into the title bar. React can re-render
+ // its own group inside the code block afterwards, so also remove any
+ // stray groups left outside the title bar to avoid a duplicate button.
+ const groups = wrapper.querySelectorAll('[class*="buttonGroup"]');
+ let kept = actions.querySelector('[class*="buttonGroup"]');
+ groups.forEach((group) => {
+ if (group.closest('.code-title-bar__actions')) return; // already in the bar
+ if (!kept) {
+ actions.appendChild(group); // move the first one into the bar
+ kept = group;
+ } else {
+ group.remove(); // drop duplicates left in the code area
+ }
+ });
};
+ // Run now and keep watching: React may re-insert a group after our move.
requestAnimationFrame(() => requestAnimationFrame(move));
+ const observer = new MutationObserver(move);
+ observer.observe(wrapper, { childList: true, subtree: true });
+ // Stop observing shortly after mount once the DOM has settled.
+ setTimeout(() => observer.disconnect(), 2000);
}, []);
// Ref callback for the terminal wrapper. Only relocates the action buttons
From 9a1d755101d580aa9aa2ae821777c1314988f499 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 12:43:11 +0200
Subject: [PATCH 31/55] Align endpoint tab pills and unify request/response
border color
In API endpoint blocks: align the tab pills' left edge with the terminal window (24px) via the first pill's margin, give the tab bar a 12px vertical padding (half the horizontal inset) so the active pill isn't cramped against the top border, and match the request tabs container border color to the response block's border.
---
docusaurus/src/scss/tabs.scss | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index 494425331a..c0912429e7 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -48,6 +48,12 @@
border-radius: var(--strapi-radius-md, 10px);
border: solid 1px var(--strapi-neutral-150);
overflow: hidden; // Prevents children from overflowing the border-radius
+
+ // In API endpoint blocks, match the response block's border color so the
+ // request (tabs) and response outer borders look identical.
+ .api-endpoint-block & {
+ border-color: var(--strapi-border-strong);
+ }
.margin-top--md {
margin-top: 24px !important;
@@ -91,6 +97,17 @@
}
}
+ // In API endpoint blocks, align the tab pills with the terminal window's
+ // left edge (24px) and give the tab bar a vertical padding of half that
+ // (12px) so the active pill isn't cramped against the block's top border.
+ .api-endpoint-block & {
+ padding: 12px 0;
+
+ [role="tab"]:nth-child(1) {
+ margin-left: 24px !important;
+ }
+ }
+
// Active tab styles
[aria-selected="true"] {
border-bottom: none;
From a8eaa6decb9746a61867e19d7d9d6f667066e7d4 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 14:42:39 +0200
Subject: [PATCH 32/55] Harmonize code block spacing, radius, borders and Ask
AI icon
Match the tab bar's bottom gap to the top gap above the pills; use the admonition corner radius (4px) on request/response/terminal blocks; drop the extra top padding above titleless request code inside tabs; make the request tabs border match the response border in both light and dark; and use the filled sparkle icon for the Ask AI button, matching the navbar.
---
docusaurus/src/scss/code-block.scss | 16 ++++++++++++++
docusaurus/src/scss/tabs.scss | 29 ++++++++++++++++++++-----
docusaurus/src/theme/CodeBlock/index.js | 4 ++--
3 files changed, 42 insertions(+), 7 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 54d5af34a1..898df0ea52 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -859,3 +859,19 @@ pre.prism-code {
}
}
}
+
+/* ──────────────────────────────────────────────────────
+ API endpoint code blocks: match the admonition corner radius
+ ────────────────────────────────────────────────────── */
+// The request (tabs), response, and terminal blocks used a 10px radius while
+// admonitions use 4px. Align them to the admonition radius (--strapi-radius-xs)
+// so all boxed content on the page shares the same corners. Scoped to endpoints.
+.api-endpoint-block {
+ .tabs-container,
+ [class*="responses"] [class*="codeBlockContainer"],
+ .code-block-enhanced {
+ border-radius: var(--strapi-radius-xs) !important;
+ }
+ // The terminal window's inner corners (title bar top / code block bottom)
+ // are set to --strapi-radius-xs directly in tabs.scss.
+}
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index c0912429e7..eda650aa18 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -50,9 +50,12 @@
overflow: hidden; // Prevents children from overflowing the border-radius
// In API endpoint blocks, match the response block's border color so the
- // request (tabs) and response outer borders look identical.
+ // request (tabs) and response outer borders look identical in both light
+ // and dark. The response uses --custom-code-block-border-color, so reuse
+ // that exact variable here rather than --strapi-border-strong (which
+ // resolves to a different value in dark mode).
.api-endpoint-block & {
- border-color: var(--strapi-border-strong);
+ border-color: var(--custom-code-block-border-color);
}
.margin-top--md {
@@ -69,6 +72,13 @@
padding: 16px 20px;
}
+ // In API endpoint blocks, use a 21px top padding so the gap between the
+ // tab bar's bottom border and the terminal window matches the gap above
+ // the active tab pill (harmonized vertical spacing).
+ .api-endpoint-block & [role="tabpanel"] {
+ padding-top: 21px;
+ }
+
// Remove border for nested tabs container
[role="tabpanel"] .tabs-container {
@@ -148,6 +158,9 @@
// Drop the container's own left padding; the tab panel's left padding
// provides the code's left inset, lining it up with the response code.
padding-left: 0 !important;
+ // Drop the container's top padding too: the tab panel already provides
+ // the space above the code, so the extra 24px just pushed it down.
+ padding-top: 0 !important;
// A titleless code block inside a tab panel has no bar to host the
// action buttons, so lift the button group up into the empty space
@@ -178,14 +191,14 @@
margin: 0 4px;
border: 1px solid var(--custom-code-block-border-color);
border-bottom: 1px solid var(--code-title-bar-border);
- border-radius: var(--strapi-radius-md) var(--strapi-radius-md) 0 0;
+ border-radius: var(--strapi-radius-xs) var(--strapi-radius-xs) 0 0;
}
.theme-code-block {
margin: 0 4px !important;
border: 1px solid var(--custom-code-block-border-color) !important;
border-top: none !important;
- border-radius: 0 0 var(--strapi-radius-md) var(--strapi-radius-md) !important;
+ border-radius: 0 0 var(--strapi-radius-xs) var(--strapi-radius-xs) !important;
}
}
}
@@ -241,7 +254,13 @@ details {
:root body {
--tabs-active-bg: rgba(73, 69, 255, 0.2); // Slightly different background in dark mode
}
-
+
+ // Match the response block's dark-mode border (which uses --strapi-neutral-200)
+ // so the request (tabs) and response outer borders stay identical in dark too.
+ .api-endpoint-block .tabs-container {
+ border-color: var(--strapi-neutral-200);
+ }
+
.tabs__item:not(.tabs__item--active) {
color: var(--strapi-neutral-400);
}
diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js
index 7c781b7f60..2efc434253 100644
--- a/docusaurus/src/theme/CodeBlock/index.js
+++ b/docusaurus/src/theme/CodeBlock/index.js
@@ -69,7 +69,7 @@ function useInjectAIButton(ref, language, codeContent, showAI) {
btn.className = 'clean-btn ai-button-injected';
btn.title = 'Ask AI to explain this code';
btn.setAttribute('aria-label', 'Ask AI to explain this code example');
- btn.innerHTML = 'Ask AI ';
+ btn.innerHTML = 'Ask AI ';
btn.addEventListener('click', () => handleAskAI(language, codeContent));
container.prepend(btn);
@@ -104,7 +104,7 @@ function TerminalTitleBar({ language, title, showAI, codeContent }) {
aria-label="Ask AI to explain this code example"
onClick={() => handleAskAI(language, codeContent)}
>
-
+
Ask AI
)}
From 6cf162b220be89430455f80452c82960228561e5 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 14:52:22 +0200
Subject: [PATCH 33/55] Apply terminal radius and code alignment to all
terminal blocks
Move the 4px corner radius onto .code-block-enhanced itself and raise the specificity of the container padding reset so standalone terminal blocks (outside API endpoints, e.g. the quick-start guide) get the same 4px corners and left-aligned code (under the first title-bar dot) as those inside endpoints.
---
docusaurus/src/scss/code-block.scss | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 898df0ea52..dda3ea62b7 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -323,10 +323,11 @@ pre.prism-code {
────────────────────────────────────────────────────── */
.code-block-enhanced {
- // The wrapper provides the border, radius, and background
+ // The wrapper provides the border, radius, and background. Use the same
+ // corner radius as admonitions (--strapi-radius-xs) for all terminal blocks.
position: relative;
border: solid 1px var(--custom-code-block-border-color);
- border-radius: var(--strapi-radius-md);
+ border-radius: var(--strapi-radius-xs);
overflow: hidden;
transition: border-color var(--strapi-duration-fast) var(--strapi-ease);
margin-bottom: var(--ifm-leading);
@@ -366,10 +367,15 @@ pre.prism-code {
}
// Code block container inside enhanced wrapper
- // All backgrounds are transparent — the wrapper controls the bg
+ // All backgrounds are transparent — the wrapper controls the bg.
+ // The :not(:has(codeBlockTitle)) variants raise specificity to beat the
+ // generic `.theme-code-block[codeBlockContainer]:not(:has(title)) { padding:24px }`
+ // rule, so terminal code isn't pushed in by that 24px padding.
.theme-code-block,
.theme-code-block[class*="codeBlockContainer"],
- .theme-code-block [class*="codeBlockContainer"] {
+ .theme-code-block[class*="codeBlockContainer"]:not(:has([class*="codeBlockTitle"])),
+ .theme-code-block [class*="codeBlockContainer"],
+ .theme-code-block [class*="codeBlockContainer"]:not(:has([class*="codeBlockTitle"])) {
padding: 0 !important;
box-shadow: none !important;
background: transparent !important;
From 56c03c717a99fb008aca500995ce7c1bd1b0f23e Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:00:20 +0200
Subject: [PATCH 34/55] Align response block header and code with the active
status pill, and remove terminal-in-tab top gap
---
docusaurus/src/scss/tabs.scss | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index eda650aa18..c991df9bce 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -73,12 +73,28 @@
}
// In API endpoint blocks, use a 21px top padding so the gap between the
- // tab bar's bottom border and the terminal window matches the gap above
- // the active tab pill (harmonized vertical spacing).
+ // tab bar's bottom border and the code matches the gap above the active
+ // tab pill (harmonized vertical spacing).
.api-endpoint-block & [role="tabpanel"] {
padding-top: 21px;
}
+ // Exception: when the tab panel holds a terminal block, drop the top
+ // padding to 0 — the terminal's own title bar already provides the spacing,
+ // so the 21px just left an empty gap between the tab bar and the window.
+ .api-endpoint-block & [role="tabpanel"]:has(.code-block-enhanced) {
+ padding-top: 0;
+ }
+
+ // Response blocks (200/404 status tabs): the active status pill sits at
+ // 24px (nth-child margin-left), but the panel's default 20px left padding
+ // left the status header (● 200 OK) and the JSON's opening `{` 4px to the
+ // left of the pill. Bump the response panel's left padding to 24px so the
+ // dot, the label, and the code all line up with the active pill's left edge.
+ .api-endpoint-block [class*="responses"] & [role="tabpanel"] {
+ padding-left: 24px;
+ }
+
// Remove border for nested tabs container
[role="tabpanel"] .tabs-container {
From d40f798dd3ab2b74ca47de8af535d7e6c14bd94b Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:03:45 +0200
Subject: [PATCH 35/55] Preserve bottom padding of framed last children
(admonitions, code) in details blocks
---
docusaurus/src/scss/details.scss | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/docusaurus/src/scss/details.scss b/docusaurus/src/scss/details.scss
index 7987c35c54..7ccc09a235 100644
--- a/docusaurus/src/scss/details.scss
+++ b/docusaurus/src/scss/details.scss
@@ -81,10 +81,18 @@ details.alert {
}
> *:last-child {
- padding-bottom: 0 !important;
margin-bottom: 0 !important;
}
+ // Strip the bottom padding of a plain (unframed) last child so its text does
+ // not add space on top of the block's own bottom padding. Framed blocks
+ // (admonitions, code blocks, tab containers) are excluded: their internal
+ // padding is part of their box, and zeroing it collapses their content
+ // against their own border.
+ > *:last-child:not(.theme-admonition):not([class*="admonition"]):not([class*="codeBlock"]):not(.tabs-container):not(.code-block-enhanced) {
+ padding-bottom: 0 !important;
+ }
+
// Only neutralize the top spacing of the first inner element, NOT the
// content wrapper itself: the wrapper keeps its padding-top so the content
// is separated from the summary (and its bottom border when open).
From 70ef80cae22676241794fc23dab0e660276e4031 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:12:00 +0200
Subject: [PATCH 36/55] Align in-tab code with the tab label text and drop the
button group below the tab bar
---
docusaurus/src/scss/tabs.scss | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index c991df9bce..4ddaf4aac3 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -171,19 +171,23 @@
// Drop the default bottom margin: it left more empty space below the
// code than above it, unbalancing the block inside the tab panel.
margin-bottom: 0 !important;
- // Drop the container's own left padding; the tab panel's left padding
- // provides the code's left inset, lining it up with the response code.
- padding-left: 0 !important;
+ // Inset the code so its first character lines up with the left edge of
+ // the tab labels' TEXT (the "cURL" word), not the tab button box. The
+ // panel already provides 20px; add 18px so the code starts at ~38px,
+ // matching the tab label (button left 24px + its 14px inner padding).
+ padding-left: 18px !important;
// Drop the container's top padding too: the tab panel already provides
// the space above the code, so the extra 24px just pushed it down.
padding-top: 0 !important;
// A titleless code block inside a tab panel has no bar to host the
- // action buttons, so lift the button group up into the empty space
- // above the code instead of overlapping the first lines. Scoped to tab
- // panels only, so response blocks (outside any tab) keep top:0.
+ // action buttons. Sit the button group just below the tab bar's bottom
+ // border (in the gap above the code) rather than straddling that border.
+ // The group is ~33px tall and the gap is ~23px, so it necessarily
+ // overlaps something: we let it overlap the code's right margin (bottom)
+ // instead of the tab bar (top), which reads much cleaner.
[class*="buttonGroup"] {
- top: -32px;
+ top: -17px;
}
}
From b3322e3cd05c250e31faeaeb8e283d51b91aa62f Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:14:47 +0200
Subject: [PATCH 37/55] Align response header and code with the status pill
label text
---
docusaurus/src/scss/tabs.scss | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index 4ddaf4aac3..fdfe08ae03 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -86,13 +86,19 @@
padding-top: 0;
}
- // Response blocks (200/404 status tabs): the active status pill sits at
- // 24px (nth-child margin-left), but the panel's default 20px left padding
- // left the status header (● 200 OK) and the JSON's opening `{` 4px to the
- // left of the pill. Bump the response panel's left padding to 24px so the
- // dot, the label, and the code all line up with the active pill's left edge.
+ // Response blocks (200/404 status tabs): align the status header
+ // (● 200 OK) and the JSON code with the left edge of the active status
+ // pill's TEXT — the "200" label, not the pill box. The pill box sits at
+ // 24px and its inner padding is 14px, so the label starts at ~38px. Give
+ // the panel a 38px left padding so the header (a direct child) lines up
+ // with the label; the code container's own padding is neutralized below so
+ // it inherits the same 38px inset.
.api-endpoint-block [class*="responses"] & [role="tabpanel"] {
- padding-left: 24px;
+ padding-left: 38px;
+
+ [class*="codeBlockContainer"]:not(:has([class*="codeBlockTitle"])) {
+ padding-left: 0 !important;
+ }
}
From d2a6668ba5d97f1e51a2dae684c0f3fa400a0adb Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:18:19 +0200
Subject: [PATCH 38/55] Match Ask AI button icon and label to the copy/wrap
buttons (neutral color, shared opacity)
---
docusaurus/src/scss/code-block.scss | 20 +++++---------------
1 file changed, 5 insertions(+), 15 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index dda3ea62b7..0c48fba33b 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -639,29 +639,19 @@ pre.prism-code {
border: none;
transition: all 0.2s ease;
+ // Match the copy/wrap buttons exactly: same neutral icon+label color and the
+ // same 0.6→1 opacity fade (applied by the shared .clean-btn rules below).
+ // This button also carries .clean-btn, so we only need to size the icon here
+ // and NOT recolor it — a colored (purple) icon made Ask AI stand out from the
+ // neutral copy/wrap icons sitting right next to it on hover.
i {
font-size: 13px;
- color: var(--strapi-primary-500);
}
span {
- color: var(--strapi-neutral-600);
font-size: 11px;
font-weight: 600;
}
-
- // On hover only darken the label + icon; keep the background unchanged.
- // !important overrides the more specific .theme-code-block .clean-btn color
- // rules (these buttons also carry the clean-btn class).
- &:hover {
- i {
- color: var(--strapi-primary-700) !important;
- }
-
- span {
- color: var(--strapi-neutral-800) !important;
- }
- }
}
// Desktop: Button opacity behavior
From 81ba8dc84dab5434c6d41bfad82ee44a86f0f33c Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:22:04 +0200
Subject: [PATCH 39/55] Fix terminal block rendering when it is a direct child
of a details/StepDetails block
---
docusaurus/src/scss/details.scss | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/docusaurus/src/scss/details.scss b/docusaurus/src/scss/details.scss
index 7ccc09a235..87dcf611f0 100644
--- a/docusaurus/src/scss/details.scss
+++ b/docusaurus/src/scss/details.scss
@@ -80,6 +80,15 @@ details.alert {
padding: var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal);
}
+ // A terminal code block (.code-block-enhanced) sitting as a direct child of a
+ // details/alert must keep its own zero padding: the rule above would push its
+ // title bar and code 20px inward, which detaches them from the terminal frame
+ // and draws a full-width divider line (the bug seen in Quick Start Step 2).
+ // Inside a TabItem the wrapper already has padding:0, so this restores parity.
+ > .code-block-enhanced {
+ padding: 0;
+ }
+
> *:last-child {
margin-bottom: 0 !important;
}
From a2c1977419d7931a693828926b515f569f1facee Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:25:41 +0200
Subject: [PATCH 40/55] Balance top and bottom spacing of code-only tabs in API
endpoint blocks
---
docusaurus/src/scss/tabs.scss | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index fdfe08ae03..d546383839 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -72,11 +72,13 @@
padding: 16px 20px;
}
- // In API endpoint blocks, use a 21px top padding so the gap between the
- // tab bar's bottom border and the code matches the gap above the active
- // tab pill (harmonized vertical spacing).
+ // In API endpoint blocks, use a symmetric 21px top and bottom padding: the
+ // top matches the gap above the active tab pill, and the bottom matches the
+ // top so the code sits evenly between the tab bar and the block's bottom
+ // border (the container's own 24px bottom padding is zeroed out below).
.api-endpoint-block & [role="tabpanel"] {
padding-top: 21px;
+ padding-bottom: 21px;
}
// Exception: when the tab panel holds a terminal block, drop the top
@@ -182,9 +184,12 @@
// panel already provides 20px; add 18px so the code starts at ~38px,
// matching the tab label (button left 24px + its 14px inner padding).
padding-left: 18px !important;
- // Drop the container's top padding too: the tab panel already provides
- // the space above the code, so the extra 24px just pushed it down.
+ // Drop the container's top AND bottom padding: the tab panel provides
+ // the space above and below the code. Without this the container's own
+ // 24px bottom padding stacked on the panel's bottom padding, leaving far
+ // more empty space below the code than above it.
padding-top: 0 !important;
+ padding-bottom: 0 !important;
// A titleless code block inside a tab panel has no bar to host the
// action buttons. Sit the button group just below the tab bar's bottom
From 4fc954ba20108f5d991329c3a8f232d37469444a Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:27:28 +0200
Subject: [PATCH 41/55] Align terminal code with the first title-bar dot in
endpoint request tabs
---
docusaurus/src/scss/tabs.scss | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index d546383839..ec1059012e 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -217,6 +217,13 @@
margin: 0 !important;
background: transparent !important;
+ // Undo the 18px left inset applied to titleless code containers above:
+ // a terminal aligns its code under the first title-bar dot via its own
+ // inner padding, so the extra 18px pushed the command too far right.
+ [class*="codeBlockContainer"]:not(:has([class*="codeBlockTitle"])) {
+ padding-left: 0 !important;
+ }
+
.code-title-bar {
border-radius: 0;
margin: 0 4px;
From c4aa189efe421f7249b1804aa73a0b59e3ea5630 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:29:54 +0200
Subject: [PATCH 42/55] Align the status header with the code for single-status
responses
---
.../components/ApiReference/api-reference.module.scss | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index b1923e4d96..5b4544af39 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -732,6 +732,15 @@
font-size: 11px;
}
+// Single-status responses (no 200/404 tabs) render the header as a direct child
+// of .responses, flush at 0px while the JSON code sits at 24px. Inset the header
+// so the pulsing dot + "200 OK" line up with the code's opening `{`. In the
+// multi-status case the header lives inside a tab panel (not a direct child),
+// so this rule does not touch it — that alignment is handled in tabs.scss.
+.responses > .responseHeader {
+ padding-left: 24px;
+}
+
.responseDot {
width: 6px;
height: 6px;
From 6c94203d7dc52878590b8b0fbf757f367b88091c Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:33:38 +0200
Subject: [PATCH 43/55] Keep terminal title bar padding when the terminal is a
direct child of details
---
docusaurus/src/scss/details.scss | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/docusaurus/src/scss/details.scss b/docusaurus/src/scss/details.scss
index 87dcf611f0..07e94a703b 100644
--- a/docusaurus/src/scss/details.scss
+++ b/docusaurus/src/scss/details.scss
@@ -105,7 +105,10 @@ details.alert {
// Only neutralize the top spacing of the first inner element, NOT the
// content wrapper itself: the wrapper keeps its padding-top so the content
// is separated from the summary (and its bottom border when open).
- > div > *:first-child {
+ // Exclude a terminal's title bar (.code-title-bar): it is the first child of
+ // the .code-block-enhanced wrapper and needs its own 10px top padding to keep
+ // the dots, "terminal" label, and copy button vertically centered.
+ > div > *:first-child:not(.code-title-bar) {
padding-top: 0 !important;
margin-top: 0 !important;
}
From 9d1257e4a2d2e7c0177d6543b22dae16840d0675 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:37:11 +0200
Subject: [PATCH 44/55] Color the terminal Ask AI sparkle glyph to match the
copy/wrap icons
---
docusaurus/src/scss/code-block.scss | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 0c48fba33b..240428dbe1 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -276,11 +276,19 @@ pre.prism-code {
// Same color + opacity as the copy/wrap buttons (which use --strapi-fg-1
// at 0.6 opacity), so all three action buttons match at rest. !important
// beats the legacy .clean-btn rules (this button also carries clean-btn).
+ // The sparkle is a Phosphor fill glyph rendered via ::before, which does
+ // not inherit the 's color (it defaults to neutral-600, a purple-grey),
+ // so color the ::before explicitly to match the neutral copy/wrap icons.
i, span {
color: var(--strapi-fg-1) !important;
opacity: 0.6 !important;
}
+ i,
+ i::before {
+ color: var(--strapi-fg-1) !important;
+ }
+
i {
font-size: 12px;
}
From 3c5b336736414063dd8448b70c1b192a2757c993 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:40:58 +0200
Subject: [PATCH 45/55] Raise terminal copy/wrap icon opacity so thin stroke
icons don't look washed out
---
docusaurus/src/scss/code-block.scss | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 240428dbe1..8cdb959357 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -445,13 +445,14 @@ pre.prism-code {
border: 1px solid var(--strapi-neutral-200) !important;
border-radius: var(--strapi-radius-md) !important;
- // Match the reference copy/wrap buttons: the icon is dimmed at rest
- // (opacity 0.6) and goes full opacity on hover — this is what makes it
- // look grey rather than solid black. !important beats the legacy
+ // Dim the icon at rest so it reads grey rather than solid black, going
+ // full opacity on hover. Copy/wrap are thin stroke SVGs, which look washed
+ // out next to Ask AI's filled glyph at the same opacity, so use 0.75 (not
+ // 0.6) to match their perceived weight. !important beats the legacy
// opacity:1 rules on .clean-btn icons.
svg, i::before, span {
color: var(--strapi-fg-1) !important;
- opacity: 0.6 !important;
+ opacity: 0.75 !important;
}
&:hover svg,
From 976034f1072bfeaf6a98e6d904e35adb2bbfc332 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 16:02:44 +0200
Subject: [PATCH 46/55] Fix terminal copy button: restore click in details,
remove ghost check/copy icon
---
docusaurus/src/scss/code-block.scss | 43 ++++++++++++++++---------
docusaurus/src/theme/CodeBlock/index.js | 29 +++++++++--------
2 files changed, 43 insertions(+), 29 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 8cdb959357..c4f635eb37 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -249,9 +249,14 @@ pre.prism-code {
background: var(--code-title-bar-lang-bg) !important;
}
- svg, i::before, span {
+ // Do not force opacity here: the more specific rules inside
+ // .code-block-enhanced handle the rest/hover dimming. Forcing opacity:1 on
+ // every svg also lit up the copy button's stacked success (check) icon,
+ // which Docusaurus keeps at opacity 0 until a copy succeeds — leaving a
+ // ghost icon behind the visible one. Only set color, and never touch the
+ // success icon's opacity.
+ svg:not([class*="copyButtonSuccessIcon"]), i::before, span {
color: var(--code-title-bar-lang-color) !important;
- opacity: 1 !important;
}
}
@@ -438,26 +443,29 @@ pre.prism-code {
width: 34px;
height: 34px;
padding: 6.4px;
- // The button itself stays fully opaque; the whole actions row is what
- // fades in/out on hover. Overrides the legacy .clean-btn opacity:0.6.
- opacity: 1 !important;
background: var(--strapi-neutral-0) !important;
border: 1px solid var(--strapi-neutral-200) !important;
border-radius: var(--strapi-radius-md) !important;
- // Dim the icon at rest so it reads grey rather than solid black, going
- // full opacity on hover. Copy/wrap are thin stroke SVGs, which look washed
- // out next to Ask AI's filled glyph at the same opacity, so use 0.75 (not
- // 0.6) to match their perceived weight. !important beats the legacy
- // opacity:1 rules on .clean-btn icons.
+ // Dim the whole BUTTON at rest so its icon reads grey rather than solid
+ // black, going full opacity on hover. Copy/wrap are thin stroke SVGs that
+ // look washed out next to Ask AI's filled glyph at the same opacity, so
+ // use 0.75 (not 0.6) to match their perceived weight.
+ //
+ // Dimming the button (not its icons) is deliberate: the copy button
+ // stacks two SVGs (copy icon + success check) and toggles which is visible
+ // by flipping their individual opacities. Touching the icon opacities here
+ // would override that toggle and leave the hidden icon bleeding through as
+ // a ghost. Dimming the button lets Docusaurus's 0/1 toggle work untouched.
+ opacity: 0.75 !important;
+ transition: opacity 0.2s ease;
+
+ // Color the icons so they invert correctly in dark mode.
svg, i::before, span {
color: var(--strapi-fg-1) !important;
- opacity: 0.75 !important;
}
- &:hover svg,
- &:hover i::before,
- &:hover span {
+ &:hover {
opacity: 1 !important;
}
}
@@ -678,7 +686,10 @@ pre.prism-code {
.clean-btn {
opacity: 1 !important;
- svg,
+ // Exclude the copy button's success (check) icon: Docusaurus keeps it at
+ // opacity 0 until a copy succeeds, so forcing an opacity here would make
+ // the check bleed through as a ghost behind the copy icon.
+ svg:not([class*="copyButtonSuccessIcon"]),
i::before,
span {
opacity: 0.6;
@@ -689,7 +700,7 @@ pre.prism-code {
}
.clean-btn:hover {
- svg,
+ svg:not([class*="copyButtonSuccessIcon"]),
i::before,
span {
opacity: 1 !important;
diff --git a/docusaurus/src/theme/CodeBlock/index.js b/docusaurus/src/theme/CodeBlock/index.js
index 2efc434253..a1b2de1922 100644
--- a/docusaurus/src/theme/CodeBlock/index.js
+++ b/docusaurus/src/theme/CodeBlock/index.js
@@ -148,20 +148,23 @@ export default function CodeBlockWrapper(props) {
const move = () => {
const actions = wrapper.querySelector('.code-title-bar__actions');
if (!actions) return;
- // Move the native copy/wrap group into the title bar. React can re-render
- // its own group inside the code block afterwards, so also remove any
- // stray groups left outside the title bar to avoid a duplicate button.
- const groups = wrapper.querySelectorAll('[class*="buttonGroup"]');
- let kept = actions.querySelector('[class*="buttonGroup"]');
- groups.forEach((group) => {
- if (group.closest('.code-title-bar__actions')) return; // already in the bar
- if (!kept) {
- actions.appendChild(group); // move the first one into the bar
- kept = group;
- } else {
- group.remove(); // drop duplicates left in the code area
- }
+ // Relocate the native copy/wrap group into the title bar. React may
+ // re-render a FRESH group inside the code block after we move one; that
+ // fresh group is the live one (its click handlers are wired), while the
+ // one we moved earlier becomes a detached, dead clone. So whenever a group
+ // appears outside the bar, treat it as the live one: drop whatever stale
+ // group we previously parked in the bar and move the fresh one in. This
+ // keeps the working button (and fixes copy being dead inside StepDetails).
+ const groups = Array.from(wrapper.querySelectorAll('[class*="buttonGroup"]'));
+ const outside = groups.filter((g) => !g.closest('.code-title-bar__actions'));
+ if (outside.length === 0) return; // nothing new to relocate
+ // The last one in document order is the most recently rendered (live) one.
+ const live = outside[outside.length - 1];
+ // Remove any other groups (stale relocated one in the bar + extra dupes).
+ groups.forEach((g) => {
+ if (g !== live) g.remove();
});
+ actions.appendChild(live);
};
// Run now and keep watching: React may re-insert a group after our move.
requestAnimationFrame(() => requestAnimationFrame(move));
From b52fb2dbcfb31cdf7293e194cd5d6297f3f44d70 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 16:05:09 +0200
Subject: [PATCH 47/55] Keep the method pill compact and top-aligned next to
long wrapping URLs
---
.../components/ApiReference/api-reference.module.scss | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index 5b4544af39..4840ce7c83 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -197,7 +197,10 @@
&__methodRow {
display: flex;
- align-items: center;
+ // Top-align so the method pill stays next to the FIRST line of a long URL
+ // that wraps onto several lines, instead of being vertically centered
+ // against the whole wrapped block.
+ align-items: flex-start;
gap: 12px;
margin-bottom: 20px;
}
@@ -274,6 +277,10 @@
letter-spacing: 0.02em;
position: relative;
overflow: hidden;
+ // Keep the pill a fixed, compact size next to long URLs: never shrink in the
+ // flex row and never let the verb ("GET") wrap onto a second line ("GE"/"T").
+ flex-shrink: 0;
+ white-space: nowrap;
&::after {
content: '';
From 3de1576694bc6213ad0d39047a45f4249bdbb139 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 16:09:03 +0200
Subject: [PATCH 48/55] Dim only the terminal action icons, not the button
border, matching Ask AI
---
docusaurus/src/scss/code-block.scss | 35 ++++++++++++++++++-----------
1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index c4f635eb37..2987e8aa73 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -447,26 +447,35 @@ pre.prism-code {
border: 1px solid var(--strapi-neutral-200) !important;
border-radius: var(--strapi-radius-md) !important;
- // Dim the whole BUTTON at rest so its icon reads grey rather than solid
- // black, going full opacity on hover. Copy/wrap are thin stroke SVGs that
- // look washed out next to Ask AI's filled glyph at the same opacity, so
- // use 0.75 (not 0.6) to match their perceived weight.
- //
- // Dimming the button (not its icons) is deliberate: the copy button
- // stacks two SVGs (copy icon + success check) and toggles which is visible
- // by flipping their individual opacities. Touching the icon opacities here
- // would override that toggle and leave the hidden icon bleeding through as
- // a ghost. Dimming the button lets Docusaurus's 0/1 toggle work untouched.
- opacity: 0.75 !important;
- transition: opacity 0.2s ease;
+ // The button (and its border) stays fully opaque; only the ICON is dimmed
+ // to 0.6 at rest and goes to 1 when the button itself is hovered — the
+ // exact treatment of the Ask AI button, so all three match in light/dark.
+ opacity: 1 !important;
// Color the icons so they invert correctly in dark mode.
svg, i::before, span {
color: var(--strapi-fg-1) !important;
}
+ // Dim the ICON only (never the border). The copy button stacks two SVGs
+ // (copy icon + success check) inside a [class*="copyButtonIcons"] wrapper
+ // and toggles which is visible via each svg's own opacity, so dim the
+ // WRAPPER (0.6 × the inner 1/0 toggle preserves the toggle, no ghost)
+ // rather than the raw svgs. The wrap button has a plain svg, and Ask AI a
+ // glyph in i::before; dim those too.
+ [class*="copyButtonIcons"],
+ > svg,
+ i::before {
+ opacity: 0.6 !important;
+ transition: opacity 0.2s ease;
+ }
+
&:hover {
- opacity: 1 !important;
+ [class*="copyButtonIcons"],
+ > svg,
+ i::before {
+ opacity: 1 !important;
+ }
}
}
}
From 69ee6fcc0d5f582c6324fec05dff087fc1d06a2e Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 16:12:26 +0200
Subject: [PATCH 49/55] Nudge the copy icon opacity up to match the perceived
weight of the other action icons
---
docusaurus/src/scss/code-block.scss | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/docusaurus/src/scss/code-block.scss b/docusaurus/src/scss/code-block.scss
index 2987e8aa73..a31e1f7a00 100644
--- a/docusaurus/src/scss/code-block.scss
+++ b/docusaurus/src/scss/code-block.scss
@@ -470,6 +470,14 @@ pre.prism-code {
transition: opacity 0.2s ease;
}
+ // The copy glyph is two thin overlapping outlined rectangles: far fewer
+ // inked pixels than Ask AI's solid star or the wrap button's thick bars,
+ // so at the same 0.6 opacity it READS lighter. Nudge just the copy icon
+ // up to ~0.78 so its perceived weight matches the other two.
+ [class*="copyButtonIcons"] {
+ opacity: 0.78 !important;
+ }
+
&:hover {
[class*="copyButtonIcons"],
> svg,
From 232f96674d34534d0eb23afcfda0b5b5485a744e Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 16:18:05 +0200
Subject: [PATCH 50/55] Lower the button group in code-only request tabs by
10px
---
docusaurus/src/scss/tabs.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index ec1059012e..dc0c30d1a7 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -198,7 +198,7 @@
// overlaps something: we let it overlap the code's right margin (bottom)
// instead of the tab bar (top), which reads much cleaner.
[class*="buttonGroup"] {
- top: -17px;
+ top: -7px;
}
}
From 797449327937cd7850aa3a4c04bf5da50495ab5f Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 16:25:16 +0200
Subject: [PATCH 51/55] Lower the button group in code-only request tabs by
16px
---
docusaurus/src/scss/tabs.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docusaurus/src/scss/tabs.scss b/docusaurus/src/scss/tabs.scss
index dc0c30d1a7..ba8005dceb 100644
--- a/docusaurus/src/scss/tabs.scss
+++ b/docusaurus/src/scss/tabs.scss
@@ -198,7 +198,7 @@
// overlaps something: we let it overlap the code's right margin (bottom)
// instead of the tab bar (top), which reads much cleaner.
[class*="buttonGroup"] {
- top: -7px;
+ top: 9px;
}
}
From 892901d32d6be38acfdc039edd658c5c1637d364 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 16:27:16 +0200
Subject: [PATCH 52/55] Lower the endpoint URL by 12px to align it with the
method pill
---
docusaurus/src/components/ApiReference/api-reference.module.scss | 1 +
1 file changed, 1 insertion(+)
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index 4840ce7c83..b996e6dce5 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -209,6 +209,7 @@
font-family: var(--strapi-font-family-mono);
font-size: 14px;
color: var(--strapi-fg-2);
+ padding-top: 12px;
}
// JS API signature (Document Service etc.): shown instead of a method pill +
From 648e5a511c61ece2663162c3f32a3deca55938a3 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 16:28:55 +0200
Subject: [PATCH 53/55] Reduce endpoint URL top padding to 6px so it centers
with the method pill
---
.../src/components/ApiReference/api-reference.module.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index b996e6dce5..419d1bbfc0 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -209,7 +209,7 @@
font-family: var(--strapi-font-family-mono);
font-size: 14px;
color: var(--strapi-fg-2);
- padding-top: 12px;
+ padding-top: 6px;
}
// JS API signature (Document Service etc.): shown instead of a method pill +
From 84cc2a47b20eb69e48e67d918bbd5141db2479e4 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 16:29:59 +0200
Subject: [PATCH 54/55] Fine-tune previous padding
---
.../src/components/ApiReference/api-reference.module.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docusaurus/src/components/ApiReference/api-reference.module.scss b/docusaurus/src/components/ApiReference/api-reference.module.scss
index 419d1bbfc0..96308b7954 100644
--- a/docusaurus/src/components/ApiReference/api-reference.module.scss
+++ b/docusaurus/src/components/ApiReference/api-reference.module.scss
@@ -209,7 +209,7 @@
font-family: var(--strapi-font-family-mono);
font-size: 14px;
color: var(--strapi-fg-2);
- padding-top: 6px;
+ padding-top: 2px;
}
// JS API signature (Document Service etc.): shown instead of a method pill +
From 492c176f896e0237ea9b19528731e8e7fea74e28 Mon Sep 17 00:00:00 2001
From: Pierre Wizla <4233866+pwizla@users.noreply.github.com>
Date: Tue, 21 Jul 2026 16:30:07 +0200
Subject: [PATCH 55/55] Delete unwanted linebreak
---
docusaurus/docs/cms/quick-start.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/docusaurus/docs/cms/quick-start.md b/docusaurus/docs/cms/quick-start.md
index a021617f3f..acac1f7128 100644
--- a/docusaurus/docs/cms/quick-start.md
+++ b/docusaurus/docs/cms/quick-start.md
@@ -166,7 +166,6 @@ sources={{
/>
Once Strapi has restarted, "Restaurant" is listed under _Content Manager > Collection types_ in the navigation. Wow, you have just created your very first content-type! It was so cool, let's create another one right now, just for pleasure.
-