# Redacted Text Display

Redacted Text Display [#redacted-text-display]

The **Redacted Text Display** renders source text with detected entities replaced inline by color-coded redaction tokens (e.g. `[PER]`, `[LOC]`), each styled per entity type and tooltipped with its type. It includes a scanning loading skeleton and an empty placeholder. Pass the original text plus the detected entity spans (with `start`/`end` offsets); segmentation happens internally.

**When to use it:** reviewing the output of `useExtractEntities` for NER, PII redaction, or content moderation.

Preview [#preview]

```tsx
'use client';

import { RedactedTextDisplay } from '@/components/redacted-text-display';

const TEXT =
  'Ada Lovelace worked with Charles Babbage on the Analytical Engine in London.';

// Offsets computed against TEXT.
const ENTITIES = [
  { text: 'Ada Lovelace', type: 'PER', start: 0, end: 12, score: 0.99 },
  { text: 'Charles Babbage', type: 'PER', start: 25, end: 40, score: 0.98 },
  { text: 'Analytical Engine', type: 'MISC', start: 48, end: 65, score: 0.82 },
  { text: 'London', type: 'LOC', start: 69, end: 75, score: 0.97 },
];

/**
 * Demo for the RedactedTextDisplay component, used by the docs live preview.
 * Renders inline color-coded redaction tokens from a sample NER result.
 * Fully local.
 */
export default function RedactedTextDisplayDemo() {
  return (
    <div className="max-w-xl">
      <RedactedTextDisplay text={TEXT} entities={ENTITIES} />
    </div>
  );
}
```

Installation [#installation]

```bash
npx shadcn@latest add @localmode/ui/results/redacted-text-display
```

Dependencies [#dependencies]

* **Data source:** renders the `text` plus `entities` spans you pass — works with any backend. Recommended producer: `useExtractEntities` (NER) from `@localmode/react` (optional). See [Bring your own data](/docs/bring-your-own-data#results--insights).

* `clsx` + `tailwind-merge` — via the shared `cn()` util

Files installed [#files-installed]

* `redacted-text-display.tsx` — the component
* `lib/utils.ts` — the `cn()` helper (if not already present)

Props [#props]

**RedactedTextDisplay**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `text` | `string` | — | **Required.** The original source text. |
| `entities` | `array` | — | **Required.** The detected entity spans (each with `start`/`end` offsets). |
| `registry` | `EntityTypeRegistry` | `the built-in PER/LOC/ORG/MISC registry` | Per-type display config (label + color). Types absent from the registry render with a default color. |
| `isScanning` | `boolean` | `false` | When true, render a scanning skeleton instead of text. |
| `emptyState` | `ReactNode` | `"Nothing to display"` | Rendered when there is no text. |

Examples [#examples]

From extracted entities [#from-extracted-entities]

```tsx
import { RedactedTextDisplay } from '@/components/redacted-text-display';
import { useExtractEntities } from '@localmode/react';

export function Example({ model, text }) {
  const { data, isLoading, execute } = useExtractEntities({ model });
  // Call execute(text) to run NER; `data` holds the result.
  return (
    <>
      <button onClick={() => execute(text)}>Scan</button>
      <RedactedTextDisplay
        text={text}
        entities={data?.entities ?? []}
        isScanning={isLoading}
      />
    </>
  );
}
```

Custom type colors [#custom-type-colors]

```tsx
<RedactedTextDisplay
  text={text}
  entities={entities}
  registry={{ EMAIL: { label: 'Email', color: 'var(--color-rose-500)' } }}
/>
```

Customization [#customization]

Tokens are tinted with the registry color at low opacity (`color26`) over `bg-card`, falling back to a muted color for unregistered types. Tooltips use the native `title` attribute (no extra dependency). The exported `segmentText()` helper performs the offset-based interleaving — overlapping spans are resolved by keeping the earliest — so you can reuse or test it independently.