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

# `lr-dataset-viewer`

- **Import** `import '@aceshooting/lyra-ui/components/lr-dataset-viewer.js';` (stable tag alias; registers the tag)
- **Class** `LyraDatasetViewer`, also available unregistered from `@aceshooting/lyra-ui/components/viewers/dataset-viewer/dataset-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, 3 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-dataset-viewer`

Fetches tab-, pipe-, or delimiter-separated text and renders a virtualized, accessible table (a
`role="table"` container with a sticky `role="row"` header, composed with `<lr-virtual-list
item-role="row">` for the body) using the optional `papaparse` peer. The document registry matches
`.tsv`, `.psv`, and `.dat` filenames.

Adopts `DocumentAnchorTarget`: a `cell-range` anchor addresses the raw file grid, 1-based, with the
header row always occupying row 1 (this component always parses with a header row, so the first row
is never part of the virtualized body); `scrollToAnchor()` scrolls the addressed row into view via
the virtualized list's `active-item-id`. `highlights` paint as a `part="cell-highlight"` cell wrapping a
focusable `part="cell-highlight-action"` native button, keeping the ARIA table tree intact. A jump
whose document is replaced by a concurrent `src` reassignment mid-flight reports `found: false`
rather than a phantom success, and a header-row target scrolls with the same
`prefers-reduced-motion`-gated smooth behavior every other row uses.

**Properties:** `src: string = ''`, `name: string = ''`, `maxHeight: string = ''` (attribute
`max-height`), and `scrollMode: DatasetViewerScrollMode = 'self'` (attribute `scroll-mode`,
reflected). Invalid CSS `max-height` values, declaration breaks, and `url()` are ignored.
`scrollMode='self'` preserves contained horizontal scrolling and applies `maxHeight`.
`scrollMode='page'` removes intervening scroll containers and the height cap, so a populated table's
sticky header follows the page scrollport while rows continue below it. The border and rounded
header corners remain; a wide dataset can overflow its host in page mode.
Unsupported attribute and untyped property values normalize to `'self'`.
Host `aria-label` names the table by attribute presence, including an explicitly empty value;
`name` and the localized row-count caption are fallbacks. The same computed name (host `aria-label`,
else `name`) also names a persistent `role="region"` landmark on `[part='base']` in _every_ fetch
state — idle, loading, empty, error, loaded — so a landmark-navigating screen-reader user reaches the
viewer before it has any rows, not only after a successful non-empty load. With neither set,
`[part='base']` stays a plain wrapper rather than an unnamed region. The outer region carries the
plain display name while the inner `[part='table']` keeps the richer row-count caption; the two are
complementary, matching `lr-csv-viewer`/`lr-archive-viewer`'s base-vs-content split.
`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 search over
every body cell's raw string value, 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 cursor.

**Events:** `lr-render-error` with `detail.error` when fetching or parsing fails. Up to 100
PapaParse diagnostics also emit this event when the recoverable partial table remains rendered, so
malformed or extra cells are never silently presented as a clean parse; exceeding that diagnostic
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` (a persistent `role="region"` named by the host `aria-label` or `name`, in
every fetch state), `body`, `table`, `header-row`, `header-cell`, `data-row`, `cell`,
`cell-highlight` (a `role="cell"` covered by a `highlights` entry; wraps the action button),
`cell-highlight-action` (the native button filling a highlighted cell — focusable, emits
`lr-highlight-activate` on click or Enter/Space; its complete accessible name uses the localized
`cellHighlightWithLabel` message with independent `{value}` and `{label}` placeholders), `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` render inside the internal `<lr-virtual-list>` and are
forwarded via `exportparts`, so `lr-dataset-viewer::part(cell)` reaches them from a consumer
stylesheet.

**Exports:** `DatasetTable` is `{ fields: string[]; rows: Record<string, string>[] }`;
`DatasetViewerScrollMode` is `'self' | 'page'`.

**Themeable custom properties:** `--lr-dataset-viewer-max-height` (default `none`) — maximum block
size of `[part="body"]`; also settable via the `max-height` property, which writes this token inline.
Page scroll mode deliberately ignores this cap.
`--lr-dataset-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.
`--lr-dataset-viewer-header-row-bg` (default `var(--lr-color-brand-quiet)`) — background of the
sticky header row, independent of the highlight outline above.

**Optional peer dependency:** `papaparse`.

Remote resources are capped at 25 MB. A quote-aware scan stops before PapaParse at 10,000 data rows,
1,000 fields in any row, 1,000,000 aggregate cells (including the header), or more than 100 parser
diagnostics; streaming record callbacks enforce the same ceilings again. Exceeding any ceiling
surfaces the localized `documentPreviewResourceTooLarge` message instead of a partial table.
