Modern TypeScript utilities for rendering arbitrary JSON as safe, themed, human-friendly HTML.
json-html-kit is designed for reports, admin tools, demos, documentation pages and support dashboards where a raw JSON tree is too technical, but building a custom view is too slow.
- TypeScript types are generated from the source.
- ESM-only package with no runtime dependencies.
- Marked as side-effect free for bundlers.
- CI runs
npm ci,typecheck,build, andtest. - Tested on Node.js 20 and 22 with GitHub Actions.
- Designed to work without framework lock-in.
- Render unknown JSON into readable HTML without framework lock-in.
- Escape user data by default.
- Use native
<details>for collapsible nested structures. - Detect arrays of objects and render them as tables.
- Provide theme presets plus a CSS variable surface for custom branding.
- Work in browsers, Vite apps, docs sites and server-side HTML generation.
npm install json-html-kitRender a standalone HTML fragment with styles included:
import { renderJsonToHtml } from 'json-html-kit';
const report = {
customer: 'Ada',
invoices: [
{ id: 'INV-001', total: 120, paid: true },
{ id: 'INV-002', total: 80, paid: false }
]
};
const html = renderJsonToHtml(report, {
theme: 'clean',
includeStyles: true
});Render into an existing page:
import { renderJsonToElement } from 'json-html-kit';
const container = document.querySelector('#report');
if (container) {
renderJsonToElement(report, container, {
theme: 'clean'
});
}json-html-kit works well as the final rendering step for data produced by small parsing utilities.
Render terminal table output as browsable JSON:
import { renderJsonToHtml } from 'json-html-kit';
import { parseTerminalTable } from 'terminal-table-kit';
const rows = parseTerminalTable(psOutput, {
keyStyle: 'camel'
});
const html = renderJsonToHtml(rows, {
theme: 'clean',
tableMode: 'auto'
});Inspect unknown JSON structure before rendering it:
import { getPathEntries } from 'object-key-paths';
import { renderJsonToHtml } from 'json-html-kit';
const html = renderJsonToHtml(getPathEntries(payload), {
theme: 'clean',
tableMode: 'auto'
});For report tables, use array-table-kit when you need Markdown or plain HTML table output instead of a nested JSON viewer.
For CSV exports from the same records, use json-csv-kit:
import { jsonToCsv } from 'json-csv-kit';
import { renderJsonToHtml } from 'json-html-kit';
const html = renderJsonToHtml(rows, {
theme: 'clean',
tableMode: 'auto'
});
const csv = jsonToCsv(rows);Returns an HTML string.
renderJsonToHtml(data, {
theme: 'slate',
tableMode: 'auto',
collapseDepth: 2,
maxArrayItems: 100,
maxObjectKeys: 100,
maxStringLength: 2000,
tablePageSize: 50,
sortKeys: true,
includeStyles: true
});Renders directly into a DOM element and injects the selected theme CSS into the document once by default. Pass includeStyles: false if your app already loads the theme CSS.
Creates a renderer with shared defaults.
Returns scoped CSS for one of the built-in themes: clean, slate, paper, terminal.
Returns a complete <style> tag for server-side templates or static HTML generation.
Injects or updates a scoped theme <style> tag in a browser document.
Creates a small DOM viewer with optional top-level array pagination.
import { createJsonHtmlViewer } from 'json-html-kit';
const viewer = createJsonHtmlViewer(container, hugeRows, {
theme: 'clean',
pageSize: 100
});
viewer.nextPage();
viewer.getPageInfo();
viewer.setPage(10);
viewer.destroy();The viewer is intentionally separate from renderJsonToHtml. The renderer stays static and string-based; the viewer owns DOM state for pagination.
Use getPageInfo() or getPageCount() when your UI needs to render its own pagination controls.
Presets are only a starting point. You can pass a custom theme object anywhere a preset name is accepted.
Use createTheme when you want to keep a preset structure but override a few visual tokens.
import { createTheme, getThemeStyleTag, renderJsonToHtml } from 'json-html-kit';
const theme = createTheme(
{
name: 'brand',
background: '#f8fbff',
surface: '#ffffff',
surfaceAlt: '#edf4ff',
text: '#172033',
muted: '#607089',
border: '#c8d7ef',
accent: '#7c3aed',
code: '#0f766e',
radius: '10px'
},
'clean'
);
const html = `
${getThemeStyleTag(theme)}
${renderJsonToHtml(data, {
theme,
collapseDepth: 2,
tableMode: 'auto'
})}
`;For a fully custom theme, provide every token:
import type { JsonHtmlTheme } from 'json-html-kit';
const theme: JsonHtmlTheme = {
name: 'dashboard',
background: '#0b1020',
surface: '#121a2f',
surfaceAlt: '#19233d',
text: '#eef4ff',
muted: '#9fb0cc',
border: '#2b3856',
accent: '#6ee7b7',
code: '#fde68a',
radius: '12px',
shadow: '0 18px 45px rgba(0, 0, 0, 0.35)',
fontFamily: 'Inter, ui-sans-serif, system-ui, sans-serif',
monoFontFamily: '"SFMono-Regular", Consolas, monospace'
};The generated CSS is scoped by default to .jhk. Pass a second argument to getThemeCss(theme, 'my-json-report') when you need a custom scope class.
json-html-kit renders static HTML. For huge API responses or log-like JSON, keep rendering bounded with limits:
const html = renderJsonToHtml(largePayload, {
maxArrayItems: 100,
maxObjectKeys: 100,
maxStringLength: 2000,
tablePageSize: 50
});These limits do not mutate your data. They only control how much HTML is generated:
maxArrayItemslimits rendered items in regular arrays.maxObjectKeyslimits rendered keys in large objects.maxStringLengthtruncates very long strings.tablePageSizelimits rendered rows when an array of objects is displayed as a table.
When content is omitted, the renderer adds a summary row such as 124 items omitted.
For full top-level array browsing, use the DOM viewer:
createJsonHtmlViewer(container, hugeRows, {
pageSize: 100
});String values and keys are escaped by default. Set allowHtml: true only for trusted content.
MPL-2.0