# Scored Result Bar List

Scored Result Bar List [#scored-result-bar-list]

The **Scored Result Bar List** renders any ranked `{label, score}` output as a vertical list: each row shows the label, a formatted confidence percentage (via `ConfidenceScoreBadge`), and an animated horizontal fill bar proportional to the 0–1 score, with the top row highlighted. It ships with a skeleton-loading state and an empty-state slot so it drops straight into async hook flows.

**When to use it:** one data contract serves every ranked-output hook — `useClassify`, `useClassifyZeroShot`, `useDetectObjects`, `useFillMask`, and reranked / `useSemanticSearch` results.

Preview [#preview]

```tsx
'use client';

import { useState } from 'react';
import { ScoredResultBarList } from '@/components/scored-result-bar-list';

const SAMPLE = [
  { label: 'technology', score: 0.91 },
  { label: 'business', score: 0.62 },
  { label: 'sports', score: 0.34 },
  { label: 'politics', score: 0.12 },
];

/**
 * Demo for the ScoredResultBarList component, used by the docs live preview.
 * Toggles between a static ranked list, the skeleton-loading state, and the
 * empty state. Fully local — no model download.
 */
export default function ScoredResultBarListDemo() {
  const [mode, setMode] = useState<'data' | 'loading' | 'empty'>('data');

  return (
    <div className="flex flex-col gap-4">
      <div className="flex gap-2">
        {(['data', 'loading', 'empty'] as const).map((m) => (
          <button
            key={m}
            type="button"
            onClick={() => setMode(m)}
            className={
              'rounded-md border border-border px-3 py-1 text-xs font-medium ' +
              (mode === m
                ? 'bg-primary text-primary-foreground'
                : 'bg-card text-card-foreground hover:bg-accent')
            }
          >
            {m}
          </button>
        ))}
      </div>
      <ScoredResultBarList
        results={mode === 'data' ? SAMPLE : []}
        isLoading={mode === 'loading'}
      />
    </div>
  );
}
```

Installation [#installation]

```bash
npx shadcn@latest add @localmode/ui/results/scored-result-bar-list
```

Dependencies [#dependencies]

* **Data source:** renders `Array<{ label, score }>` you pass — works with any backend (classifier, search ranker, or a constant). Recommended producers: `useClassify` / `useClassifyZeroShot` / `useSemanticSearch` from `@localmode/react`. See [Bring your own data](/docs/bring-your-own-data#results--insights).

* `ConfidenceScoreBadge` — the per-row percentage badge (installed automatically as a registry dependency)

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

Files installed [#files-installed]

* `scored-result-bar-list.tsx` — the component
* `confidence-score-badge.tsx` — the embedded badge
* `lib/utils.ts` — the `cn()` helper (if not already present)

Props [#props]

**ScoredResultBarList**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `results` | `array` | — | **Required.** The scored results to render. Any ranked-output hook fits this contract: `useClassify` / `useClassifyZeroShot` / `useDetectObjects` / `useFillMask` / `useSemanticSearch`. |
| `isLoading` | `boolean` | `false` | When true, render staggered skeleton rows instead of results. |
| `skeletonRows` | `number` | `4` | Number of skeleton rows shown while loading. |
| `highlightTop` | `boolean` | `true` | Whether to highlight the top-ranked (first) row. |
| `sort` | `boolean` | `true` | Whether to sort results by score (descending) before rendering. Set false if the input is already ranked and you want to preserve its order. |
| `limit` | `number` | — | Maximum number of rows to render after sorting. |
| `emptyState` | `ReactNode` | `"No results"` | Rendered when there are no results and the list is not loading. |

Examples [#examples]

Zero-shot classification [#zero-shot-classification]

```tsx
import { ScoredResultBarList } from '@/components/scored-result-bar-list';
import { useClassifyZeroShot } from '@localmode/react';

export function Example({ model }) {
  const { data, isLoading } = useClassifyZeroShot({ model });
  // classifyZeroShot() returns parallel `labels` / `scores` arrays.
  const results = (data?.labels ?? []).map((label, i) => ({
    label,
    score: data.scores[i],
  }));
  return <ScoredResultBarList results={results} isLoading={isLoading} />;
}
```

Limit to the top 3, preserve input order [#limit-to-the-top-3-preserve-input-order]

```tsx
<ScoredResultBarList results={detections} sort={false} limit={3} />
```

Custom empty state [#custom-empty-state]

```tsx
<ScoredResultBarList results={[]} emptyState={<span>Run a query to see results</span>} />
```

Customization [#customization]

Each row uses shadcn/ui token utilities (`bg-card`, `border-border`, `bg-primary/5` for the top row). The proportional fill bar is a positioned `<div>` whose width is the row's score relative to the max — adjust its color classes in the copied file. The per-row percentage is delegated to `ConfidenceScoreBadge`, so tier colors stay consistent with the rest of your results UI.