Cell Renderers
Four ready-made display components for common data types — star ratings, progress bars, coloured chips and status badges. Drop one into a column's template and it picks up the active theme on its own.
gc-rating
Stars, read-only or clickable. The display understands halves; the interaction does not — and the two columns here are the same data side by side so you can see it.
Click a star in the second column.Halves are a display feature, not an input one
[value]="4.5" renders four full stars and one half — the fraction clips the fill of
the star it lands on, so 3.2 works too. The Rating column above is
full of halves.
The interactive column is a different story. Each star is a real
<button>, and clicking star i emits i —
a whole number. There is no gesture for half a star: click any of the 4.5 rows above and the line
under the grid shows a 4 or a 5, never the 4.5 it started from. If half values matter for input,
pair the stars with a number editor rather than expecting the click to express them.
<gc-rating [value]="row.rating" [readonly]="false"
(valueChange)="setRating(row, $event)" />
The handler gets the value; what you do with it is yours. This example hands it straight back to
the grid with applyTransaction({ update: [row] }), which is why
both rating columns move when you click — they read the same field, and the row repaints.
Changing the array your data source read from would repaint nothing: the grid keeps its own copy
of the data, and a transaction is how you reach it.
Read-only is the default
Left alone the component renders as a picture: [readonly] is true, the
stars are plain spans, and the whole group carries one label reading "4.5 out of 5".
[max] changes how many stars are drawn, [size] their pixel size, and
[color] overrides the fill.
gc-progress
A bar filled to value ÷ max. Both columns read the same stock number against a different max, so the second one runs out of bar — the fill is clamped, never overflowing.
The bar is value ÷ max, and it is clamped
Both columns above read the same progress number. The first uses the default
[max]="100", so the label matches the value. The second sets
[max]="50" — a stock level of 82 is 164% of a reorder point of 50, and the bar
stops at full rather than running past its track. The label rounds what it shows.
<gc-progress [value]="row.progress" [max]="50" [showLabel]="true" [height]="10" />
The label is yours if you want it
[showLabel]="true" overlays the rounded percentage. [label] replaces it
with any string — "3 of 8 seats" reads better than "38%" when the number is a
count. [height] sets the bar thickness and the corners follow it, and
[color] overrides the fill for a single column.
gc-chip
Tag pills on one line. What does not fit collapses into a “+N” pill that opens the rest in a popover — try the keyboard row, which carries thirty tags, and drag the column edge to watch the count change.
Chips stay on one line, and the rest go into a “+N”
This is the part worth knowing before you use it. Chips never wrap. Whatever does not fit collapses into a +N pill, and clicking that pill opens the hidden chips in a popover. The keyboard in the third row carries thirty tags, which is what makes the behaviour visible at this width.
The popover uses the browser's own popover layer, so it escapes the cell's clipping and the grid's scroll container. It closes on Esc, on a click outside, and on any scroll.
Fitting: measured, or fixed
- Left unset — the component measures the column and shows as many chips as fit on one line, keeping room for the +N. It re-measures when the column is resized: drag the Tags (fit) edge and the count follows.
[maxVisible]="2"— a fixed cap, no measuring. The Tags (max 2) column always shows two chips and a +N for the rest, whatever the width.
Colour and shape
[colorMap] assigns a colour per exact tag string — the left column tints
Electronics, Lighting and New that way, and anything unlisted falls
back to the theme default. [color] is the single-colour version for when every chip
in the column should match. Three shapes via [variant]: soft (the
default tint), solid, and outline — the right column above.
[value] takes a single string as happily as an array, so a one-tag column needs no
special case.
gc-badge
A status pill in one of five semantic colours. Anything your data can hold that the map does not cover falls back to neutral — the last row shows it.
Five statuses, and always a fallback
[status] is one of neutral, success,
warning, error or info. Each resolves to a theme colour,
with the pill's background a low-alpha tint of that same colour, so a badge stays legible in
every theme without a per-theme override. [dot]="true" adds the leading dot.
Map your own values to those five, and give the map a fallback — the last row
above has a status the map has never seen, and it renders as neutral with the raw
value as its label rather than as an empty pill.
badge(row: Product) {
return STATUS_BADGE[row.status] ?? { status: 'neutral', label: row.status };
}
Four zero-dependency cell renderers
gridcraft ships four small standalone display components built to drop straight into a column
through cellTemplate. They are pure SVG and CSS, carry no runtime dependencies, and
read their colours from the --gc-* custom properties — so light, dark and material
all work with nothing to configure.
All four are in the free package. Import the component, put it in an
<ng-template>, and point a column's cellTemplate at it.
Give a renderer column a prop as well
A cellTemplate decides what is drawn. It has no effect on the value behind
the cell, and nothing outside the screen ever runs it — sorting, filtering and export all read
the field. So a renderer column with a prop sorts by its number and exports as its
number, which is almost always what you want:
{ key: 'rating', name: 'Rating', prop: 'rating',
cellTemplate: this.ratingTpl, sortable: true }
Sort the Rating column above — the stars reorder by value, not by anything the
component drew. A column with no prop is left out of an exported file
automatically, so excludeFromExport is only worth setting on a column that has a
field and still should not be in the file — such as the second view of one, above.
These four cover common shapes, not every shape. When none of them fits, a plain
cellTemplate takes any markup or component you like — see
Custom Templates.
Renderer components
| Property | Type | Default | Description |
|---|---|---|---|
| gc-rating | [value] [max] [size] [color] [readonly] (valueChange) | max: 5, size: 16, readonly: true | Stars, with fractional display (4.5 draws a half). Interactive when [readonly]="false"; a click emits a whole number. |
| gc-progress | [value] [max] [showLabel] [label] [height] [color] | max: 100, height: 8, showLabel: false | Bar filled to value ÷ max, clamped to 0–100%. label replaces the computed percentage. |
| gc-chip | [value] [colorMap] [color] [variant] [maxVisible] | variant: 'soft' | Tag pills on one line; the overflow collapses into a “+N” that opens a popover. maxVisible unset means fit-to-width. |
| gc-badge | [value] [status] [dot] | status: 'neutral', dot: false | Status pill — status: neutral | success | warning | error | info, each mapped to a theme colour. |
| column.cellTemplate | TemplateRef<CellContext<T>> | — | The wiring point — drop any renderer inside an ng-template and point the column at it. |
| column.prop | keyof T | string | — | Keep it on a renderer column: it is what sorting and export read, since neither runs the template. |
| column.excludeFromExport | boolean | false | Only needed when a column HAS a prop and still should not reach the file. A prop-less column is skipped already. |