# Sticky Cells
URL: https://pro.rv-grid.com/api/sticky-cells/
Source: src/content/docs/api/sticky-cells.md
## Module Extensions

### `ColumnRegular` (Extended from `@revolist/revogrid`)

```ts
interface ColumnRegular {
  /**
       * Defines whether a cell participates in StickyCellsPlugin row discovery.
       *
       * Use this for sticky behavior and keep `cellProperties` focused on cell
       * styling, attributes, and event props.
       */
      stickyCell?: StickyCellPredicate
}
```

---

### `AdditionalData` (Extended from `@revolist/revogrid`)

```ts
interface AdditionalData {
  /**
       * Sticky cells plugin configuration.
       *
       * ```ts
       * grid.additionalData = {
       *   stickyCells: { maxRows: 2 },
       * };
       * ```
       */
      stickyCells?: StickyCellsConfig
}
```

## Plugin API

### `StickyCellsConfig`

```ts
interface StickyCellsConfig {
  /**
     * Maximum amount of active sticky rows appended to `pinnedTopSource`.
     *
     * The nearest sticky row is appended last, so it renders closest to the
     * scrollable body after any user-defined pinned top rows.
     *
     * @default 1
     */
    maxRows?: number;
  /**
     * Makes plugin-managed sticky pinned rows readonly.
     *
     * This only affects the cloned rows rendered in `rowPinStart`; original source
     * rows and user-provided pinned top rows keep their normal readonly behavior.
     *
     * @default true
     */
    readonlyPinnedRows?: boolean
}
```

---

### `StickyCellPredicate`

```ts
export type StickyCellPredicate = boolean | ((params: CellTemplateProp) => boolean);
```

---

### `StickyCellsPlugin`

The `StickyCellsPlugin` keeps marked rows visible by appending the active
sticky rows to RevoGrid's pinned top row source.

Sticky cells are configured through a column `stickyCell` predicate. If any
visible cell in a row resolves `stickyCell` to `true`, that row can become an
active sticky row. The row is cloned into `rowPinStart` once it starts
crossing above the visible row viewport.

**Key Features**:
- Uses a dedicated column `stickyCell` predicate; no separate sticky row data source is required.
- Supports one or more active sticky rows pinned at the top of the scrolling row viewport.
- Activates only after the bottom edge of the source row crosses above the visible viewport.
- Preserves user-defined `pinnedTopSource` rows and removes only plugin-managed sticky rows.
- Reuses normal pinned row rendering, including `cellTemplate` and `beforecellrender` integrations.

**Behavior**:
- The last `stickyCells.maxRows` sticky rows at or above the scroll position stay active.
- User pinned top rows render first; plugin-managed sticky rows are appended after them.

### Example
```ts
import { StickyCellsPlugin } from '@revolist/revogrid-pro';

const stickyCell = ({ model }) => model.isCheckpoint === true;

const grid = document.createElement('revo-grid');
grid.plugins = [StickyCellsPlugin];
grid.columns = [
  {
    name: 'Account',
    prop: 'account',
    stickyCell,
  },
  {
    name: 'Status',
    prop: 'status',
    stickyCell,
  },
];
```

```ts
class StickyCellsPlugin {}
```

---

### `resolveActiveStickyRows`

```ts
export function resolveActiveStickyRows(
  rowIndex: number,
  context: ActiveStickyRowsContext,
): number[];
```

---

### `resolveBottomStableTreeRows`

```ts
export function resolveBottomStableTreeRows(
  rowIndex: number,
  rowCount: number,
  context: ActiveStickyRowsContext,
): number[];
```

---

### `findIndexedStickyRowsAtOrBefore`

```ts
export function findIndexedStickyRowsAtOrBefore(
  indexedStickyRows: number[],
  rowIndex: number,
  maxRows: number,
): number[];
```

---

### `filterVisibleBottomRows`

```ts
export function filterVisibleBottomRows(
  rowIndexes: number[],
  providers: PluginProviders,
  isAtBottom: () => boolean = () => isScrolledToBottom(providers),
): number[];
```

---

### `filterVisibleRows`

```ts
export function filterVisibleRows(
  rowIndexes: number[],
  providers: PluginProviders,
): number[];
```

---

### `isScrolledToBottom`

```ts
export function isScrolledToBottom(providers: PluginProviders): boolean;
```

---

### `isSameRowIndexes`

```ts
export function isSameRowIndexes(a: number[], b: number[]): boolean;
```

---

### `ActiveStickyRowsContext`

```ts
interface ActiveStickyRowsContext {
  maxRows: number;
  providers: PluginProviders;
  revogrid: HTMLRevoGridElement;
  indexedStickyRows: number[];
  includeTreeRow?: boolean;
  isAtBottom(): boolean;
  resolveStickyColumns(rowIndex: number): boolean
}
```

---

### `markCellOnlyStickyColumn`

```ts
export function markCellOnlyStickyColumn(column: ColumnRegular);
```

---

### `unmarkCellOnlyStickyColumn`

```ts
export function unmarkCellOnlyStickyColumn(column: ColumnRegular);
```

---

### `isCellOnlyStickyColumn`

```ts
export function isCellOnlyStickyColumn(column: ColumnRegular | undefined): boolean;
```

---

### `normalizeStickyCellsConfig`

```ts
export function normalizeStickyCellsConfig(
  config: StickyCellsConfig | undefined,
): Required<StickyCellsConfig>;
```

---

### `STICKY_GRID_CLASS`

```ts
STICKY_GRID_CLASS: string;
```

---

### `STICKY_ACTIVE_CLASS`

```ts
STICKY_ACTIVE_CLASS: string;
```

---

### `STICKY_PIN_ANIMATING_CLASS`

```ts
STICKY_PIN_ANIMATING_CLASS: string;
```

---

### `STICKY_PINNED_ROW_CLASS`

```ts
STICKY_PINNED_ROW_CLASS: string;
```

---

### `STICKY_PIN_ANIMATION_MS`

```ts
STICKY_PIN_ANIMATION_MS: 180;
```

---

### `STICKY_INDEX_SLICE_MS`

```ts
STICKY_INDEX_SLICE_MS: 4;
```

---

### `STICKY_INDEX_SLICE_ROWS`

```ts
STICKY_INDEX_SLICE_ROWS: 2500;
```

---

### `DEFAULT_MAX_STICKY_ROWS`

```ts
DEFAULT_MAX_STICKY_ROWS: 1;
```

---

### `StickyRowsIndexer`

```ts
class StickyRowsIndexer {
  reset();

  cancel();

  schedule(rowIndex: number, callback: () => void);

  indexSlice():;

  add(rowIndex: number);
}
```

---

### `createPinnedStickyRow`

```ts
export function createPinnedStickyRow(
  rowStore: RowStore,
  rowIndex: number,
  stickyColumns: StickyRowCache | null = null,
  cellOnly = false,
): StickyPinnedRow | null;
```

---

### `stripPluginPinnedRows`

```ts
export function stripPluginPinnedRows(source: DataType[]): DataType[];
```

---

### `isPluginPinnedRow`

```ts
export function isPluginPinnedRow(row: DataType): row is StickyPinnedRow;
```

---

### `getPluginPinnedRowStickyColumns`

```ts
export function getPluginPinnedRowStickyColumns(row: DataType): StickyRowCache | null;
```

---

### `getPluginPinnedRowSourceIndex`

```ts
export function getPluginPinnedRowSourceIndex(row: DataType): number | undefined;
```

---

### `isPluginPinnedRowCellOnly`

```ts
export function isPluginPinnedRowCellOnly(row: DataType): boolean;
```

---

### `isPluginPinnedCell`

```ts
export function isPluginPinnedCell(
  row: DataType,
  colType: DimensionCols,
  columnIndex: number,
): boolean;
```

---

### `isSamePinnedTopSource`

```ts
export function isSamePinnedTopSource(current: DataType[], next: DataType[]): boolean;
```

---

### `StickyPinnedRow` (Extended from `sticky-cells.pinned.ts`)

```ts
export type StickyPinnedRow = DataType & {
  [STICKY_PINNED_ROW_SOURCE_INDEX]?: number;
  [STICKY_PINNED_ROW_COLUMNS]?: StickyRowCache;
};
```

---

### `isStickyCell`

```ts
export function isStickyCell(model: CellTemplateProp): boolean;
```

---

### `StickyRowCache`

```ts
export type StickyRowCache = Map<DimensionCols, Set<number>>;
```

---

### `StickyCellResolver`

```ts
class StickyCellResolver {
  clear();

  resolveStickyColumns(rowIndex: number): StickyRowCache | null;

  rememberStickyCell(rowIndex: number, colType: DimensionCols, columnIndex: number);
}
```

---

### `captureVerticalScrollAnchor`

Captures the main vertical scroll state before Sticky Cells mutates
`rowPinStart`.

The returned callback must run after the pinned source update. It restores the
user's visual scroll anchor once RevoGrid has had a chance to lay out the new
pinned top height.

```ts
export function captureVerticalScrollAnchor(
  revogrid: HTMLRevoGridElement,
  options: ScrollAnchorOptions =;
```

---

### `resolveStickyCellPredicate`

```ts
export function resolveStickyCellPredicate(
  stickyCell: StickyCellPredicate | undefined,
  model: CellTemplateProp,
): boolean;
```
