# Provider Badge

Provider Badge [#provider-badge]

The **Provider Badge** displays the **resolved** provider identity — composing the
[Provider Fallback Badge](/docs/local-first/provider-fallback-badge) for the tier
and name — alongside the **model id that actually served** the request. While
`providerName` is `null` it shows a "Resolving provider…" placeholder, so the
badge never claims a provider before one has resolved.

> **How it differs from Provider Fallback Badge.** The
> [Provider Fallback Badge](/docs/local-first/provider-fallback-badge) is the
> lower-level **tier chip** (built-in vs download, plus the WASM threading
> variant). The Provider Badge **composes it** and adds two things the fallback
> badge does not: the **resolved provider identity** (with a Resolving state) and
> the **served model id**. Use the fallback badge when you only want the tier
> chip; use the Provider Badge when you want to surface which provider + model
> actually answered.

> **Presentational.** It takes generic display props (`providerName`, `tier`,
> `modelId`, `note`) — no block-local provider types. Feed it from your provider
> resolution (recommended: a provider-fallback resolver such as
> `useProviderFallback` from `@localmode/react`).

**When to use it:** a Chrome-AI ⇄ Transformers.js (or any two-tier) surface where
the user should see which provider and model actually served the last result.

Preview [#preview]

```tsx
'use client';

import { useState } from 'react';

import { ProviderBadge } from '@/components/provider-badge';

/**
 * Demo for ProviderBadge, used by the docs live preview. Toggle the "Resolving"
 * state to see the placeholder flip to a resolved built-in provider; a second
 * badge shows a download-tier provider with a served model id and a note.
 */
export default function ProviderBadgeDemo() {
  const [resolved, setResolved] = useState(true);

  return (
    <div className="flex flex-col items-start gap-3">
      <ProviderBadge
        providerName={resolved ? 'Chrome AI' : null}
        tier="built-in"
        modelId={resolved ? 'gemini-nano' : null}
      />
      <ProviderBadge
        providerName="Transformers.js"
        tier="download"
        modelId="Xenova/distilbart-cnn-6-6"
        note="Runs on-device"
      />
      <button
        type="button"
        onClick={() => setResolved((r) => !r)}
        className="rounded-md border border-border px-3 py-1.5 text-xs font-medium hover:bg-muted"
      >
        {resolved ? 'Show resolving state' : 'Resolve provider'}
      </button>
    </div>
  );
}
```

Installation [#installation]

```bash
npx shadcn@latest add @localmode/ui/local-first/provider-badge
```

Dependencies [#dependencies]

* **Data source:** renders the resolved provenance you pass — works with any backend. Recommended LocalMode source: `useProviderFallback().resolution` (optional).
* `clsx` + `tailwind-merge` — via the shared `cn()` util (installed automatically as a registry dependency)
* Composes `@localmode/ui/local-first/provider-fallback-badge` (installed automatically as a registry dependency)

Files installed [#files-installed]

* `provider-badge.tsx` — the component
* `provider-fallback-badge.tsx` — the composed tier chip
* `lib/utils.ts` — the `cn()` helper (if not already present)

Props [#props]

**ProviderBadge**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `providerName` | `string \| null` | — | **Required.** Resolved provider display name, or null while resolution is pending. |
| `tier` | `ProviderTier` | — | **Required.** The resolved provider's tier (drives the composed fallback badge). |
| `modelId` | `string \| null` | — | **Required.** The model id that actually served the most recent result, if any. |
| `note` | `string` | — | Optional note rendered after the badge (e.g. a provider disclaimer). |

Examples [#examples]

Show a resolved provider + served model [#show-a-resolved-provider--served-model]

```tsx
import { ProviderBadge } from '@/components/provider-badge';

<ProviderBadge providerName="Chrome AI" tier="built-in" modelId="gemini-nano" />
```

Drive it from a provider-fallback resolver [#drive-it-from-a-provider-fallback-resolver]

```tsx
import { useProviderFallback } from '@localmode/react';
import { ProviderBadge } from '@/components/provider-badge';

function SummarizerBadge() {
  const { resolution } = useProviderFallback();
  return (
    <ProviderBadge
      providerName={resolution?.provider === 'chrome-ai' ? 'Chrome AI' : resolution ? 'Transformers.js' : null}
      tier={resolution?.tier ?? 'download'}
      modelId={resolution?.modelId ?? null}
    />
  );
}
```

Customization [#customization]

The badge never estimates or probes — it reflects exactly the `providerName` /
`tier` / `modelId` you pass, so it can never claim a provider that did not serve
the request. Because you own the copied file, restyle the served-model line, add
a copy button, or change the "Resolving…" copy.