<!-- GENERATED by scripts/build-llms.mjs from llms/viewers.md — do not edit this file. -->

# `lr-csv-viewer`

- **Import** `import '@aceshooting/lyra-ui/components/lr-csv-viewer.js';` (stable tag alias; registers the tag)
- **Class** `LyraCsvViewer`, also available unregistered from `@aceshooting/lyra-ui/components/viewers/csv-viewer/csv-viewer.class.js`
- **Family** `components/viewers/` — see `llms/index.md` for its siblings
- **Status** `stable` since `4.0.0` — see the maturity and deprecation policy in `llms/shared.md`
- **Release history** [CHANGELOG.md](../../CHANGELOG.md)
- **Deprecations** none
- **Optional peers** `papaparse` — see `llms/peers.md`
- **Themeable via** 12 parts, 2 custom properties — see this component's own `@csspart`/`@cssprop` list below
- **Library-wide behavior** (events, form association, `locale`/`strings`, tokens, TS types): `llms/shared.md`

---

## `lr-csv-viewer`

Fetches CSV text, parses quoted fields with the optional `papaparse` peer, and virtualizes body rows.

Adopts `DocumentAnchorTarget`: a `cell-range` anchor addresses the raw file grid, 1-based, with the
header row included whenever `has-header-row` is set; `scrollToAnchor()` scrolls the addressed
row/column into view via the virtualized list's `active-item-id`. `highlights` paint as a focusable
`part="cell-highlight"`. A jump whose document is replaced by a concurrent `src` reassignment
mid-flight reports `found: false` rather than a phantom success.

**Properties:** `src: string = ''` and `name: string = ''`. `hasHeaderRow: boolean = true` (attribute
`has-header-row`) controls whether the first parsed row is rendered as a persistent header above
the virtualized row scrollport.
Host `aria-label` names both the viewer region and loaded table by attribute presence, including an
explicitly empty value; `name` and the localized label are fallbacks.
`maxHeight: string = ''` (attribute `max-height`) is a CSS length that caps the body allocation —
setting it writes `--lr-csv-viewer-max-height` inline on `[part="base"]`; invalid CSS `max-height`
values, declaration breaks, and `url()` are ignored. `anchorKinds: readonly LyraAnchorKind[] =
['cell-range']` (this viewer's supported `LyraAnchor.kind` values for the shared anchor-target
contract).

**Methods:** `search(query)` resolves the match count via a case-insensitive substring match over
the same stringified cell values `cell()` renders, ordered row then column (empty/whitespace query
behaves like `clearSearch()`); `searchNext()`/`searchPrevious()` advance/step back through matches
(wrapping, resolving `false` when there are none); `clearSearch()` clears the query, matches, and
painted marks.

**Events:** `lr-render-error` with `detail.error` when fetching or parsing reports an error. Up to
100 recoverable PapaParse diagnostics may accompany the rendered grid; exceeding that budget is a
resource-limit error instead.
`lr-highlight-activate` (`detail: { highlightId }`) — a `highlights` cell was clicked or activated via
Enter/Space. `lr-anchor-result` (`detail: { found }`) — fired after an `anchor` assignment or a
`scrollToAnchor()` call. `lr-search-change` (`detail: { query, matchCount, matchCountExact, activeIndex }`) — from
search/navigation/clear, canonical source reset, and effective-locale re-evaluation. `lr-text-select` is not part of this
grid viewer's event contract; its registry capabilities advertise `textSelect: false`.

**CSS parts:** `base`, `body` (the capped content allocation), `sheet` (the named `role="table"`),
`header-row` (persistent above the nested virtual-list row scrollport), `data-row`, `cell`, `cell-highlight` (a structural
cell covered by a `highlights` entry), `cell-highlight-action` (the native button filling a
highlighted cell; emits `lr-highlight-activate`; its complete accessible name uses the localized
`cellHighlightWithLabel` message with independent `{value}` and `{label}` placeholders; this action,
not the structural `cell-highlight`, owns keyboard focus and its focus ring), `rows`,
`spinner`, `error`, and `anchor-live-region` (an aria-hidden, non-live shadow mirror of the latest
anchor-jump message; the spoken copy is appended to the shared document-level polite sink only while
the viewer and its composed ancestors are exposed to the accessibility tree). `data-row`,
`cell`, `cell-highlight`, and `cell-highlight-action` are rendered inside the internal
`<lr-virtual-list>` and forwarded via `exportparts`, so
`lr-csv-viewer::part(cell)` reaches them from a consumer stylesheet.

**Themeable custom properties:** `--lr-csv-viewer-max-height` (default `none`) — maximum block size
allocated to `[part="body"]`; the nested virtual-list scrolls data rows in the remainder below the
header. It is also settable via the `maxHeight` property, which writes this token inline on
`[part="base"]`. `--lr-csv-viewer-highlight-color` (default
`var(--lr-color-brand)`) — the outline color of a `cell-highlight` cell. The cell matching
`activeHighlightId` receives a private warning-color default because a `[data-active]` selector
can't be chained onto the `::part(cell-highlight)` the cell reaches this component's stylesheet
through. An inherited or direct public value remains authoritative across that boundary.

**Optional peer dependency:** install `papaparse` with `pnpm add papaparse`. The registry matches
`text/csv` and `.csv` filenames.

Importing `csv-viewer.js` (this component's own registration entry) loads `<lr-csv-viewer>`'s class
module immediately. A granular consumer (not importing the `all.js` compatibility bundle) who wants
that deferred too can instead import
`@aceshooting/lyra-ui/components/viewers/csv-viewer/csv-viewer-register.js`, which installs the
same registration lazily and exports `CSV_VIEWER_TAG` (`'lr-csv-viewer'`) as a stable reference to
the tag it eventually registers.

Remote resources are capped at 25 MB. A quote-aware scan stops before PapaParse at 10,000 raw rows
(the first row consumes the same budget whether or not `has-header-row` displays it as a header),
1,000 columns in any row, 1,000,000 aggregate cells, or more than 100 parser diagnostics; streaming
row callbacks enforce the same ceilings again. Exceeding any ceiling surfaces the localized
`documentPreviewResourceTooLarge` message instead of a partial grid.

---
