Home/Cells & Formatting/Cell Renderers
Cells & Formatting

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.

Product
Rating
Rate (click)
Aurora Desk Lamp
Nimbus Office Chair
Pulse Mechanical KB
Drift Wireless Mouse
Vertex Monitor 27"
Cobalt Notebook
Halo Webcam Pro
Loft Standing Desk
Echo USB-C Hub
Slate Desk Mat
Beacon Ring Light
Atlas Laptop Stand
Orbit Cable Tray
All records loaded
13 / 13 records
Last value your handler received: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.

Product
Stock
vs. Reorder (50)
Aurora Desk Lamp
82%
100%
Nimbus Office Chair
24%
48%
Pulse Mechanical KB
95%
100%
Drift Wireless Mouse
0%
0%
Vertex Monitor 27"
61%
100%
Cobalt Notebook
12%
24%
Halo Webcam Pro
47%
94%
Loft Standing Desk
5%
10%
Echo USB-C Hub
73%
100%
Slate Desk Mat
38%
76%
Beacon Ring Light
0%
0%
Atlas Laptop Stand
88%
100%
Orbit Cable Tray
30%
60%
All records loaded
13 / 13 records

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.

Product
Tags (fit)
Tags (max 2)
Aurora Desk Lamp
LightingNewSaleTrending
LightingNew+2
SaleTrending
Nimbus Office Chair
FurnitureErgonomicHeavyAssembly Required
FurnitureErgonomic+2
HeavyAssembly Required
Pulse Mechanical KB
ElectronicsPopularRGBWirelessCompactMechanicalBacklitUSB-CHot-SwapProgrammableN-KeyAnti-GhostAluminiumTKLPBTQuietClickyLinearTactile60%75%100%GamingOfficeMacWindowsLinuxBluetooth2.4GHzWired
ElectronicsPopular+28
RGBWirelessCompactMechanicalBacklitUSB-CHot-SwapProgrammableN-KeyAnti-GhostAluminiumTKLPBTQuietClickyLinearTactile60%75%100%GamingOfficeMacWindowsLinuxBluetooth2.4GHzWired
Drift Wireless Mouse
ElectronicsWireless
ElectronicsWireless
Vertex Monitor 27"
ElectronicsNew4KHDRUSB-CIPS
ElectronicsNew+4
4KHDRUSB-CIPS
Cobalt Notebook
StationeryA5Dotted
StationeryA5+1
Dotted
Halo Webcam Pro
ElectronicsPopular1080pPlug & Play
ElectronicsPopular+2
1080pPlug & Play
Loft Standing Desk
FurnitureNewElectricHeight Adj.Wide
FurnitureNew+3
ElectricHeight Adj.Wide
Echo USB-C Hub
ElectronicsAccessories
ElectronicsAccessories
Slate Desk Mat
AccessoriesPopularXLVegan Leather
AccessoriesPopular+2
XLVegan Leather
Beacon Ring Light
LightingPhotographyAdjustableTripodWarm
LightingPhotography+3
AdjustableTripodWarm
Atlas Laptop Stand
AccessoriesNewAluminiumAdjustable
AccessoriesNew+2
AluminiumAdjustable
Orbit Cable Tray
AccessoriesDiscontinued
AccessoriesDiscontinued
All records loaded
13 / 13 records

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.

Product
Status
Aurora Desk Lamp
In Stock
Nimbus Office Chair
Low Stock
Pulse Mechanical KB
In Stock
Drift Wireless Mouse
Out of Stock
Vertex Monitor 27"
In Stock
Cobalt Notebook
Low Stock
Halo Webcam Pro
In Stock
Loft Standing Desk
Backorder
Echo USB-C Hub
In Stock
Slate Desk Mat
Low Stock
Beacon Ring Light
Out of Stock
Atlas Laptop Stand
In Stock
Orbit Cable Tray
discontinued
All records loaded
13 / 13 records

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

PropertyTypeDefaultDescription
gc-rating[value] [max] [size] [color] [readonly] (valueChange)max: 5, size: 16, readonly: trueStars, 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: falseBar 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: falseStatus pill — status: neutral | success | warning | error | info, each mapped to a theme colour.
column.cellTemplateTemplateRef<CellContext<T>>—The wiring point — drop any renderer inside an ng-template and point the column at it.
column.propkeyof T | string—Keep it on a renderer column: it is what sorting and export read, since neither runs the template.
column.excludeFromExportbooleanfalseOnly needed when a column HAS a prop and still should not reach the file. A prop-less column is skipped already.