Styling
PGrid ships a thin, opinionated default stylesheet and exposes every structural element through a stable class. You style the grid by overriding those classes, attaching your own classes via config, or both.
Three places to style
- Per cell, via config. Use
cssClasson a column, row, or cell. Most styling lives here — it's data-driven and stays close to the grid declaration. - Globally, by overriding pgrid classes. The grid emits a stable set of
.pgrid-*classes; override them in your own stylesheet to retheme. - Programmatically, via extensions. Use the
cellAfterRenderhook to add classes based on data (status-based row colors, hover effects, etc). See Extensions.
CSS class reference
Every class PGrid emits, and what it's for.
Container & panes
.pgrid | The root element you mounted into. |
.pgrid-content-pane | Wrapper holding all six panes. |
.pgrid-top-left-pane / -top-pane / -left-pane / -center-pane / -bottom-left-pane / -bottom-pane | The six freeze panes. Each contains a matching -inner wrapper. |
Cells
.pgrid-cell | Every cell — header and body. Absolutely positioned within its pane. |
.pgrid-cell-content | Inner wrapper that holds the cell text. Centered vertically. Style padding/text-align here. |
.pgrid-cell-selection | Default selection class. Override or replace via selection.cssClass. |
.pgrid-row-header | Added to every cell whose row is in the header range. |
.pgrid-text-overflow-host + .pgrid-text-ellipsis / -clip / -wrap | Set by TextOverflowExtension. Don't override unless you know what you're doing. |
Editor & scrollbar
.pgrid-cell-text-editor | The default inline text input. |
.pgrid-col-resize-handle | The drag handle injected by ColumnResizeExtension. |
.pgrid-hscroll / -vscroll / -hscroll-thumb / -vscroll-thumb | Custom scrollbar tracks and thumbs. |
Cell data-* attributes
Useful for selectors that target specific positions:
data-row-index | Visible row index (header rows are 0..headerRowCount-1). |
data-col-index | Column index. |
/* Style every cell in column 3 without using cssClass */
.pgrid-cell[data-col-index="3"] { background: #fef3c7; }
Per-column / row / cell styling
The recommended way to style — declarative and data-driven. PGrid concatenates these classes in priority order: cell > row > column. All matching classes are applied; later ones win on conflicting properties.
const grid = new PGrid({
columns: [
{ id: 0, field: 'id', title: 'ID', cssClass: 'col-id' },
{ id: 1, field: 'salary', title: 'Salary', cssClass: 'col-money' }
],
rows: [
{ i: 5, cssClass: 'row-summary', height: 40 }
],
cells: [
{ r: 5, c: 1, cssClass: 'cell-grand-total' }
],
/* … */
});
.col-money {
text-align: right;
font-variant-numeric: tabular-nums;
color: #15803d;
}
.row-summary {
font-weight: 600;
background-color: #f1f5f9;
border-top: 2px solid #cbd5e0;
}
.cell-grand-total {
background-color: #fef3c7;
}
Theming
Two practical patterns:
Scope a theme to a wrapper class
Wrap your grid in a container with a theme class, then scope your overrides under it. This lets you switch themes by toggling a single class — and host multiple themed grids on the same page.
<div class="theme-dark">
<div id="grid" style="height: 400px;"></div>
</div>
.theme-dark .pgrid-cell {
background: #0f172a;
color: #e2e8f0;
border-bottom: 1px solid #1e293b;
border-right: 1px solid #1e293b;
}
.theme-dark .grid-header-row {
background-color: #1e293b !important;
color: #f1f5f9 !important;
}
.theme-dark .grid-cell-selection {
background-color: rgba(56, 189, 248, 0.2) !important;
box-shadow: inset 0 0 0 2px #38bdf8 !important;
}
Live demo: Themes (default / compact / spreadsheet / dark switcher).
Override the LESS source
If you import the LESS sources directly (recommended only when you're already using LESS), the variables in styles/themes/default.less are overridable: @grid-cell-border, @grid-cell-bg, @grid-row-header-bg, @grid-cell-selection-bg, @grid-cell-selection-border, @grid-outer-border, @grid-column-header-bg.
Recipes
Zebra striping
Add a class on odd rows during render. Don't forget to remove it in cellAfterRecycled — cells are reused as you scroll.
const zebra = {
cellAfterRender(e) {
if (e.rowIndex % 2 === 1) e.cell.classList.add('row-zebra');
},
cellAfterRecycled(e) {
e.cell.classList.remove('row-zebra');
}
};
new PGrid({ /* … */ extensions: [zebra] });
.row-zebra { background-color: #fafbfc; }
Status-driven row color
const statusRowColor = {
cellAfterRender(e) {
if (!e.dataRow) return;
e.cell.classList.toggle('row-overdue', e.dataRow.status === 'Overdue');
e.cell.classList.toggle('row-paid', e.dataRow.status === 'Paid');
},
cellAfterRecycled(e) {
e.cell.classList.remove('row-overdue', 'row-paid');
}
};
.row-overdue { background-color: #fef2f2; }
.row-paid { background-color: #f0fdf4; }
Row hover
Light up every cell of the row under the cursor.
const rowHover = {
init(grid) { this._grid = grid; this._row = -1; },
gridAfterRender() {
this._grid.view.getElement().addEventListener('mouseover', (e) => {
const cell = e.target.closest('.pgrid-cell');
if (!cell) return;
const r = parseInt(cell.dataset.rowIndex);
if (r === this._row) return;
this._highlight(this._row, false);
this._highlight(r, true);
this._row = r;
});
},
_highlight(r, on) {
if (r < 0) return;
this._grid.view.getElement()
.querySelectorAll(`.pgrid-cell[data-row-index="${r}"]`)
.forEach(c => c.classList.toggle('row-hover', on));
}
};
.row-hover { background-color: #eff6ff !important; }
Custom selection
Pass your own class to the selection extension and style it however you like.
new PGrid({
selection: { cssClass: 'cell-selected' },
/* … */
});
.cell-selected {
background-color: #e0f2fe !important;
box-shadow: inset 0 0 0 2px #0284c7;
}
Compact mode
Tighter rows, smaller font, lighter borders. Combine config (rowHeight) with CSS.
new PGrid({ rowHeight: 24, /* … */ });
.theme-compact .pgrid-cell {
font-size: 12px;
border-right: none;
border-bottom: 1px solid #ececef;
}
Editor styling
The default text editor uses .pgrid-cell-text-editor. Custom editors render into a floating container that's appended to document.body — give it a wrapper class to scope your styles. See the Custom editors sample.
// Inside your editor's attach(e):
e.cell.classList.add('my-editor-host');
e.cell.appendChild(myInput);
.my-editor-host {
background: #fff;
box-shadow: inset 0 0 0 2px #0ea5e9, 0 4px 12px rgba(0,0,0,0.08);
border-radius: 4px;
display: flex;
align-items: stretch;
}
Scrollbars
PGrid renders its own scrollbar tracks/thumbs in .pgrid-hscroll / .pgrid-vscroll with corresponding -thumb children. Default thumbs use the browser scrollbar styling, so the easiest path is targeting ::-webkit-scrollbar on those elements.
.pgrid-hscroll::-webkit-scrollbar,
.pgrid-vscroll::-webkit-scrollbar { width: 10px; height: 10px; }
.pgrid-hscroll::-webkit-scrollbar-thumb,
.pgrid-vscroll::-webkit-scrollbar-thumb {
background: #cbd5e0;
border-radius: 5px;
}