JSON Inspector
retab-ui/json-inspectorFreeComponent
A read-only JSON viewer with theme-aware syntax highlighting and a hover copy button, plus a standalone CopyButton.
Install it
npx shadcn@latest add https://ui.retab.com/r/json-inspector.jsonSource
1"use client";23import * as React from "react";4import { Check, Copy } from "lucide-react";56import { cn } from "@/lib/utils";7import { ScrollArea } from "@/components/ui/scroll-area";8import { useKeyedMountEffect } from "@/hooks/use-keyed-mount-effect";9import { useKeyedLayoutEffect } from "@/hooks/use-keyed-layout-effect";10import { joinEffectKey } from "@/lib/effect-key";1112import {13 createJsonInspectorLineHtmlCache,14 type JsonInspectorLineHtmlCache,15} from "./json-inspector-highlight";1617const SMALL_JSON_LINE_LIMIT = 500;18const VIRTUAL_LINE_HEIGHT = 20;19const VIRTUAL_OVERSCAN = 8;20const INITIAL_VIEWPORT_HEIGHT = 480;21const MAX_RENDERED_LINES = 500;22const VIRTUAL_JSON_LINE_STYLE: React.CSSProperties = {23 height: VIRTUAL_LINE_HEIGHT,24};2526/**27 * A small copy-to-clipboard button. Shows a transient check on success; style28 * placement via `className` (e.g. absolute-position it over a panel).29 */30export function CopyButton({31 text,32 className,33}: {34 text: string;35 className?: string;36}) {37 const [copied, setCopied] = React.useState(false);3839 return (40 <button41 type="button"42 onClick={() => {43 void navigator.clipboard.writeText(text).then(() => {44 setCopied(true);45 window.setTimeout(() => setCopied(false), 1500);46 });47 }}48 className={cn(49 "text-muted-foreground hover:bg-muted hover:text-foreground rounded-md p-1.5 transition-colors",50 className,51 )}52 title="Copy"53 >54 {copied ? (55 <Check className="size-3.5 text-emerald-600 dark:text-emerald-400" />56 ) : (57 <Copy className="size-3.5" />58 )}59 </button>60 );61}6263function useJsonLineHtml() {64 const cacheRef = React.useRef<JsonInspectorLineHtmlCache | null>(null);65 if (!cacheRef.current) {66 cacheRef.current = createJsonInspectorLineHtmlCache();67 }68 const cache = cacheRef.current;6970 return React.useCallback((line: string) => cache.get(line), [cache]);71}7273function jsonLineWindow({74 lineCount,75 scrollTop,76 viewportHeight,77}: {78 lineCount: number;79 scrollTop: number;80 viewportHeight: number;81}) {82 if (lineCount <= 0) return { start: 0, end: 0 };8384 const safeScrollTop =85 Number.isFinite(scrollTop) && scrollTop > 0 ? scrollTop : 0;86 const safeViewportHeight =87 Number.isFinite(viewportHeight) && viewportHeight > 088 ? viewportHeight89 : INITIAL_VIEWPORT_HEIGHT;90 const visibleStart = clamp(91 Math.floor(safeScrollTop / VIRTUAL_LINE_HEIGHT),92 0,93 lineCount - 1,94 );95// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from retab-ui
All 130 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Alertalert | retab-ui | Components | Free | 1 dep | |
| Alert Dialogalert-dialog | retab-ui | Components | Free | 1 dep | |
| Aspect Ratioaspect-ratio | retab-ui | Components | Free | no deps | |
| Attachment Sidebarattachment-sidebar | retab-ui | Components | Free | 1 dep | |
| Autocompleteautocomplete | retab-ui | Components | Free | 2 deps | |
| Calendarcalendar | retab-ui | Components | Free | 2 deps | |
| Code Viewercode-viewer | retab-ui | Components | Free | 2 deps · 32 files | |
| Commandcommand | retab-ui | Components | Free | 2 deps |
