# Entity Stats Bar

Entity Stats Bar [#entity-stats-bar]

The **Entity Stats Bar** shows the total detected-entity count plus a per-type breakdown badge (colored dot + count + label) for each entity type. Counts are computed internally from a `DetectedEntity[]` (or pass a pre-computed `counts` map) against a color/label registry.

**When to use it:** summarizing the output of `useExtractEntities` (NER) — entity review, PII triage, or content moderation dashboards.

Preview [#preview]

```tsx
'use client';

import { EntityStatsBar } from '@/components/entity-stats-bar';

const ENTITIES = [
  { text: 'Ada Lovelace', type: 'PER', score: 0.99 },
  { text: 'Charles Babbage', type: 'PER', score: 0.98 },
  { text: 'London', type: 'LOC', score: 0.97 },
  { text: 'Analytical Engine', type: 'MISC', score: 0.81 },
  { text: 'Royal Society', type: 'ORG', score: 0.9 },
  { text: 'Cambridge', type: 'LOC', score: 0.95 },
];

/**
 * Demo for the EntityStatsBar component, used by the docs live preview.
 * Renders a total + per-type breakdown from a sample NER result. Fully local.
 */
export default function EntityStatsBarDemo() {
  return (
    <div className="max-w-xl space-y-3">
      <EntityStatsBar entities={ENTITIES} />
      {/* Non-NER consumer: relabel the total noun via `itemNoun`. */}
      <EntityStatsBar
        counts={{ POSITIVE: 3, NEGATIVE: 3 }}
        registry={{
          POSITIVE: { label: 'Positive', color: 'var(--color-emerald-500, #10b981)' },
          NEGATIVE: { label: 'Negative', color: 'var(--color-rose-500, #f43f5e)' },
        }}
        itemNoun="result"
      />
    </div>
  );
}
```

Installation [#installation]

```bash
npx shadcn@latest add @localmode/ui/results/entity-stats-bar
```

Dependencies [#dependencies]

* **Data source:** renders the `entities` array (or a pre-computed `counts` map) 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]

* `entity-stats-bar.tsx` — the component
* `lib/utils.ts` — the `cn()` helper (if not already present)

Props [#props]

**EntityStatsBar**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `entities` | `array` | — | The detected entities to count. Either pass `entities` (counts are computed internally) or a pre-computed `counts` map. |
| `counts` | `Record<string, number>` | — | Pre-computed per-type counts, as an alternative to `entities`. |
| `registry` | `EntityTypeRegistry` | `the built-in PER/LOC/ORG/MISC registry` | Per-type display config. Types absent from the registry still render with a default color. |
| `hideEmpty` | `boolean` | `true` | Whether to hide types with a zero count. |
| `itemNoun` | `string` | `"entity"` | Singular noun for the counted items, shown before the breakdown (e.g. "6 entities"). Non-NER consumers pass their own noun — e.g. `"result"` renders "6 results" / "1 result". The plural is derived automatically. |
| `itemNounPlural` | `string` | `pluralize(itemNoun)` | Plural form of {@link itemNoun}. Defaults to a regular English pluralization of `itemNoun` ("entity" → "entities", "result" → "results"); pass this only for irregular plurals. |

Examples [#examples]

From extracted entities [#from-extracted-entities]

```tsx
import { EntityStatsBar } from '@/components/entity-stats-bar';
import { useExtractEntities } from '@localmode/react';

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

Custom type registry [#custom-type-registry]

```tsx
<EntityStatsBar
  entities={entities}
  registry={{
    EMAIL: { label: 'Email', color: 'var(--color-rose-500)' },
    PHONE: { label: 'Phone', color: 'var(--color-sky-500)' },
  }}
/>
```

Non-NER labels (`itemNoun`) [#non-ner-labels-itemnoun]

The total defaults to the NER-flavored noun ("6 entities" / "1 entity"). Non-NER consumers — sentiment tallies, classification routes, dedupe groups — relabel it with `itemNoun`; the plural is derived automatically ("result" → "results"). Pass `itemNounPlural` only for irregular plurals.

```tsx
<EntityStatsBar
  counts={{ POSITIVE: 3, NEGATIVE: 3 }}
  registry={{
    POSITIVE: { label: 'Positive', color: 'var(--color-emerald-500)' },
    NEGATIVE: { label: 'Negative', color: 'var(--color-rose-500)' },
  }}
  itemNoun="result" // renders "6 results" / "1 result"
/>
```

Customization [#customization]

Each per-type badge takes its color from the registry (defaults wired to CSS variables) and falls back to a muted color for unregistered types. The container uses `bg-card` / `border-border`. Pass `hideEmpty={false}` to always show every registered type, even at a count of zero. Set `itemNoun` (and, for irregular plurals, `itemNounPlural`) to relabel the total for non-NER use. The exported `countByType()` helper computes the tally if you need it elsewhere.