Source Code

<div class="container py-5 d-flex justify-content-center">
  <div class="card bsapi-card">
    <div class="card-body p-3">
      <div class="d-flex justify-content-between align-items-center mb-2">
        <div class="d-flex align-items-center gap-2">
          <span class="badge text-bg-success">200 OK</span>
          <span class="small text-muted">GET /api/orders/1042</span>
        </div>
        <button type="button" class="btn btn-sm btn-outline-secondary" id="bsapiCopy">Copy JSON</button>
      </div>
      <div class="bsapi-tree" id="bsapiTree"></div>
    </div>
  </div>
</div>

Bootstrap API Response Viewer — Free HTML CSS JS Snippet

Bootstrap API Response Viewer · Dashboards · Plain HTML, CSS & JS · Live preview

What's included

Features

A genuinely recursive renderer that handles JSON of any nesting depth, not a fixed two-level layout
Type-based syntax coloring — strings, numbers, and booleans each get a distinct, accurate color
Every object and array node collapses independently via its own unique generated id
"Copy JSON" re-serializes the original data object, always valid regardless of the tree's collapsed state
A status badge and endpoint label give the response real request context, not just a bare JSON dump

About this UI Snippet

Bootstrap API Response Viewer — HTML, CSS & JavaScript

Screenshot of the Bootstrap API Response Viewer snippet rendered live

renderNode() is a genuinely recursive function, not a two-level special case for "an object with some flat values" — it calls itself for every nested object or array it encounters, however deep, which is why the sample response's customer object and items array (itself an array of objects) both render correctly with the same function that handles the top-level response. A value's type decides its color entirely through valueSpan(): strings, numbers, and booleans each get their own CSS class, which is what makes the viewer's syntax coloring accurate rather than a single uniform text color for every value.

Each collapsible object or array gets a unique, incrementing id (via a closured nodeId counter) so its toggle arrow and its .bsapi-children block can find each other by that id regardless of how many other collapsible nodes exist elsewhere in the tree — collapsing the items array has zero effect on whether customer is expanded, because they're wired to completely independent ids.

"Copy JSON" copies DATA itself, re-serialized fresh with JSON.stringify(DATA, null, 2), rather than scraping the rendered HTML back into text — which guarantees the copied JSON is always valid and correctly formatted no matter what collapsed/expanded state the tree happens to be showing on screen at the time.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Hand this snippet to an AI coding assistant like Claude and ask it to add a "collapse all" / "expand all" pair of buttons that toggle every node's collapsed state at once, or to add inline key search/highlighting so a specific field name can be located quickly inside a very large response.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a Bootstrap 5.3 JSON API response viewer, using the real Bootstrap CDN framework (bootstrap.min.css and bootstrap.bundle.min.js), not custom CSS made to resemble it.

Requirements:
- A sample nested JSON object (including at least one nested object and one array of objects) rendered as a syntax-colored tree — distinct colors for string, number, and boolean values.
- Render the tree with a genuinely recursive function that handles any nesting depth, not hardcoded levels.
- Every object and array in the tree must be independently collapsible/expandable via a click on its own toggle arrow, using a unique id per node so collapsing one has no effect on any other node.
- Include a status badge (e.g. "200 OK") and a request label above the tree for context.
- Add a "Copy JSON" button that copies a freshly re-serialized, correctly formatted version of the original data object to the clipboard, regardless of the tree's current collapsed/expanded state.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Load the snippetA full JSON response renders with colored strings, numbers, and booleans, fully expanded.
  2. 2
    Click the arrow next to "items ["Just that array collapses to a single line, independent of every other node in the tree.
  3. 3
    Click the arrow againIt re-expands to show both order items exactly as before.
  4. 4
    Collapse "customer" tooBoth collapsed sections stay collapsed independently — collapsing one never affects the other.
  5. 5
    Click "Copy JSON"The complete, correctly formatted JSON is copied to the clipboard, regardless of what's currently collapsed on screen.

Real-world uses

Common Use Cases

DEV
Internal admin tools and API debugging dashboards
Pairs with bootstrap-http-status-badge for a fuller request/response inspection panel.
Webhook and integration testing tools
Inspect a payload's exact shape without leaving the app, alongside bootstrap-webhook-event-viewer-style tooling.
Learning recursive rendering techniques
A compact, complete example of rendering arbitrarily nested data with one function instead of hardcoding levels of depth.

Got questions?

Frequently Asked Questions

Yes — renderNode() calls itself for every nested object or array regardless of depth, so a response with objects nested five levels deep would render (and collapse) exactly the same way this two-level example does.

Each collapsible node gets its own unique id from an incrementing counter, and its toggle only ever looks up its own matching id's children block — there's no shared or global collapsed state that could leak between unrelated sections.

Yes. Convert renderNode() into a recursive component that renders itself for object/array values, track each node's collapsed state as a boolean (in local component state or a shared collapsed-ids Set), and keep "Copy JSON" serializing the original data object rather than reading rendered markup.

Replace the DATA constant with the parsed JSON body from an actual fetch response — renderNode() makes no assumptions about the specific shape of the object, only that it's valid JSON-compatible data (objects, arrays, strings, numbers, booleans, null).