Add this component

npx zentauri-ui add api-response-viewer

Accessibility notes

Keyboard accessible by default with semantic markup, visible focus treatment, and tokenized states. Add descriptive labels for icon-only or decorative usage.

Dependency notes

Check Installation for shared peers. This component keeps styling in Tailwind classes and the --zui-* token contract.

Data display

API Response Viewer for inspecting HTTP responses

Use the API response viewer to present an HTTP response as a compact, readable surface. A status pill colors itself by status class (1xx informational, 2xx success, 3xx redirect, 4xx client error, 5xx server error), the header strip shows the request method, URL, round-trip time, and payload size, and Body / Headers tabs switch between a pretty-printed JSON body and a key/value list of response headers — with a copy-to-clipboard control for the body.

GET200 OKhttps://api.example.com/v1/users/8f21128 ms2.4 KB
{
  "ok": true,
  "user": {
    "id": "u_8f21",
    "name": "Ada Lovelace",
    "roles": [
      "admin",
      "editor"
    ],
    "verified": true
  }
}

API response viewer playground

Pick a response, chrome appearance, and size to preview the viewer live. Switch between the Body and Headers tabs, turn on a motion preset for the tab transition, and use Show output / Show code to copy the matching snippet.


GET200 OKhttps://api.example.com/v1/users/8f21128 ms2.4 KB
{
  "ok": true,
  "user": {
    "id": "u_8f21",
    "name": "Ada Lovelace",
    "roles": [
      "admin",
      "editor"
    ],
    "verified": true,
    "lastLogin": null
  }
}

All appearances

Every shipped chrome appearance over the same response. Click any card to load it into the playground above.

{
  "ok": true,
  "user": {
    "id": "u_8f21",
    "name": "Ada Lovelace",
    "roles": [
      "admin",
      "editor"
    ],
    "verified": true,
    "lastLogin": null
  }
}
{
  "ok": true,
  "user": {
    "id": "u_8f21",
    "name": "Ada Lovelace",
    "roles": [
      "admin",
      "editor"
    ],
    "verified": true,
    "lastLogin": null
  }
}
{
  "ok": true,
  "user": {
    "id": "u_8f21",
    "name": "Ada Lovelace",
    "roles": [
      "admin",
      "editor"
    ],
    "verified": true,
    "lastLogin": null
  }
}
{
  "ok": true,
  "user": {
    "id": "u_8f21",
    "name": "Ada Lovelace",
    "roles": [
      "admin",
      "editor"
    ],
    "verified": true,
    "lastLogin": null
  }
}

Api Response Viewer API

Generated from the package prop types and variant definitions.

ApiResponseViewer

ApiResponseViewerProps

Variants

PropTypeDefault
appearance
contrastdefaultglasssubtle
default
sizeVisual scale of the viewer chrome (sm | md | lg). Named `size` to mirror the library's other display components.
lgmdsm
md

Behavior

PropTypeDefault
bodyResponse body, pretty-printed as JSON in the Body tab.unknownnone
defaultTabWhich tab is active initially.ApiResponseViewerTab | undefinednone
enableClipboardShow a copy button that copies the pretty-printed JSON body.boolean | undefinednone
headersResponse headers rendered in the Headers tab.Record<string, string> | undefinednone
labelsOverride default tab / copy copy.ApiResponseViewerLabels | undefinednone
methodRequest method, e.g. "GET".string | undefinednone
responseSizeHuman-readable response payload size, e.g. "2.4 KB".string | undefinednone
status*HTTP status code, e.g. 200, 404, 500.numbernone
statusTextReason phrase. Derived from a common-codes map (then the status class) when omitted.string | undefinednone
timeRound-trip time in milliseconds.number | undefinednone
urlRequest URL (truncated in the header).string | undefinednone
Inherited HTML props
PropTypeDefault
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLDivElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone

ApiResponseViewerVariant

ApiResponseViewerVariantProps

Behavior

PropTypeDefault
appearance'default' | 'subtle' | 'contrast' | 'glass' | null | undefinednone
size'md' | 'sm' | 'lg' | null | undefinednone

ApiResponseViewerAnimated

ApiResponseViewerAnimatedProps

animated

Behavior

PropTypeDefault
animationTransition preset for the panel content when switching tabs.ApiResponseViewerAnimation | undefinednone
appearance'default' | 'subtle' | 'contrast' | 'glass' | null | undefinednone
bodyResponse body, pretty-printed as JSON in the Body tab.unknownnone
defaultTabWhich tab is active initially.ApiResponseViewerTab | undefinednone
enableClipboardShow a copy button that copies the pretty-printed JSON body.boolean | undefinednone
headersResponse headers rendered in the Headers tab.Record<string, string> | undefinednone
labelsOverride default tab / copy copy.ApiResponseViewerLabels | undefinednone
methodRequest method, e.g. "GET".string | undefinednone
refAllows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).Ref<HTMLDivElement> | undefinednone
responseSizeHuman-readable response payload size, e.g. "2.4 KB".string | undefinednone
sizeVisual scale of the viewer chrome (sm | md | lg). Named `size` to mirror the library's other display components.NonNullable<'md' | 'sm' | 'lg' | null | undefined> | undefinednone
status*HTTP status code, e.g. 200, 404, 500.numbernone
statusTextReason phrase. Derived from a common-codes map (then the status class) when omitted.string | undefinednone
timeRound-trip time in milliseconds.number | undefinednone
urlRequest URL (truncated in the header).string | undefinednone
Inherited HTML props
PropTypeDefault
classNamestring | undefinednone
idstring | undefinednone
onClickMouseEventHandler<HTMLDivElement> | undefinednone
styleCSSProperties | undefinednone
titlestring | undefinednone
CSS variable overrides

API Response Viewer CSS variables

Override these API response viewer variables on :root, a theme selector, or a component wrapper.

68 variables

Pattern: --zui-<component>-<slot?>-<variant?>-<property>-<state?>-dark?

:root {
  --zui-api-response-viewer-border: #0000001a;
  --zui-api-response-viewer-bg: oklch(98.4% 0.003 247.858);
  --zui-api-response-viewer-fg: oklch(20.8% 0.042 265.755);
  --zui-api-response-viewer-subtle-bg: oklch(92.9% 0.013 255.508);
  --zui-api-response-viewer-contrast-bg: #ffffff;
  --zui-api-response-viewer-glass-bg: #ffffffcc;
  --zui-api-response-viewer-glass-border: #ffffff66;
  --zui-api-response-viewer-header-bg: oklch(96.8% 0.007 247.896);
  --zui-api-response-viewer-header-fg: oklch(44.6% 0.043 257.281);
  --zui-api-response-viewer-method-fg: #7c3aed;
  --zui-api-response-viewer-method-bg: #7c3aed1a;
  --zui-api-response-viewer-url-fg: #64748b;
  --zui-api-response-viewer-meta-fg: #94a3b8;
  --zui-api-response-viewer-tab-fg: oklch(44.6% 0.043 257.281);
  --zui-api-response-viewer-tab-hover-bg: #0000000d;
  --zui-api-response-viewer-tab-active-fg: #7c3aed;
  --zui-api-response-viewer-action-fg: oklch(44.6% 0.043 257.281);
  --zui-api-response-viewer-action-hover-bg: #0000000d;
  --zui-api-response-viewer-body-fg: #16a34a;
  --zui-api-response-viewer-key-fg: #7c3aed;
  --zui-api-response-viewer-value-fg: #2563eb;
  --zui-api-response-viewer-empty-fg: #94a3b8;
  --zui-api-response-viewer-info-fg: #1d4ed8;
  --zui-api-response-viewer-info-bg: #dbeafe;
  --zui-api-response-viewer-success-fg: #15803d;
  --zui-api-response-viewer-success-bg: #dcfce7;
  --zui-api-response-viewer-redirect-fg: #a16207;
  --zui-api-response-viewer-redirect-bg: #fef9c3;
  --zui-api-response-viewer-client-error-fg: #c2410c;
  --zui-api-response-viewer-client-error-bg: #ffedd5;
  --zui-api-response-viewer-server-error-fg: #b91c1c;
  --zui-api-response-viewer-server-error-bg: #fee2e2;
  --zui-api-response-viewer-neutral-fg: #475569;
  --zui-api-response-viewer-neutral-bg: #e2e8f0;
}

/* Dark theme variables follow the same names with -dark appended. */
.dark {
  --zui-api-response-viewer-border-dark: #ffffff1a;
  --zui-api-response-viewer-bg-dark: oklch(12.9% 0.042 264.695);
}

Composition and API

Pass the response details as props: status drives the status pill and its tone, statusText overrides the derived reason phrase, and method and url populate the header strip alongside time (ms) and responseSize. The body prop is pretty-printed as JSON in the Body tab, while headers renders as a key/value list in the Headers tab. defaultTab picks which tab opens first, enableClipboard toggles the copy button, and labels overrides the tab and copy copy. appearance and size control the chrome. The separate animated entry adds fade and slide motion presets for the tab-switch transition.

Accessibility

The Body and Headers tabs are real buttons with aria-selected reflecting the active tab, so keyboard and screen-reader users can switch panels. The root and every region carry data-slot attributes for styling and testing, and the status pill exposes a data-tone attribute describing its status class. The animated entry's motion is short and easing-based; pair it with prefers-reduced-motion handling in your app where needed.

Next.js integration notes

The static ApiResponseViewer entry ships no framer-motion and is safe in any Server or Client Component tree (it is a Client Component because it manages the active tab and copy state). The animated ApiResponseViewerAnimated entry imports framer-motion, which is an optional peer dependency — install it only if you use the animated entry. Both render deterministically from the same props, so server and client output match and there is no hydration mismatch.

FAQ

How is the status pill color chosen?

From the status class: 1xx is info, 2xx is success, 3xx is redirect, 4xx is a client error, 5xx is a server error, and anything else is neutral. The apiResponseStatusTone helper exposes this mapping, and each tone routes through its own --zui-api-response-viewer-* tokens with light and dark values.

Do I have to pass statusText?

No. When statusText is omitted the viewer derives a reason phrase from a built-in map of common HTTP codes (for example 404 becomes Not Found), and falls back to the status class label (such as Client Error) for unknown codes.

Do I need framer-motion?

Only for the animated entry. The default import from @zentauri-ui/zentauri-components/ui/api-response-viewer is framer-motion-free. Import ApiResponseViewerAnimated from the /animated subpath when you want fade or slide tab transitions, and install framer-motion as a peer dependency.

How do I theme the colors?

Override the --zui-api-response-viewer-* CSS variables (border, bg, fg, the per-tone status colors, tab, method, header key/value, and body) on :root, a theme selector, or a wrapper. Each variable ships a light fallback and a paired -dark variant for dark mode.