Format Cells
The Format Cells dialog provides spreadsheet-style presentation controls without changing the values stored in the grid source. Use it for number, currency, date, and time display as well as typography, colors, alignment, wrapping, and borders.
The dialog and the quick Format submenu are powered by
DataGridFormattingPlugin. Registering it also installs
DataGridContextMenuPlugin, which supplies the selection opened from cell and
column-header menus. Registering DataGridContextMenuPlugin as the entry point
continues to work and installs the same formatting runtime.
Declarative cell, row, and column formatting
Section titled “Declarative cell, row, and column formatting”Register DataGridFormattingPlugin, then use either of these declarative
inputs:
column.dataGridFormataccepts either a format for the whole column or a function that chooses a format for each cell.grid.dataGridFormattingdefines reactive whole-column, whole-row, and cell presets. Reassigning this property replaces the declarative preset state and refreshes the grid.
This complete example formats positive amounts as GBP currency and negative
amounts as EUR accounting values. The resolver receives the current row and
cell value, so no external lookup function is needed. The example does not
retrieve the plugin or call apply():
import type { ColumnRegular } from '@revolist/revogrid';import { DataGridFormattingPlugin, type DataGridCellFormat,} from '@revolist/revogrid-pro';
type InvoiceRow = { id: string; customer: string; amount: number;};
const gbpFormat: DataGridCellFormat = { // Controls how the raw cell value is displayed. value: { // Uses the built-in currency formatter. kind: 'preset', preset: 'currency', // Applies UK number and currency conventions. locale: 'en-GB', // Displays the value as British pounds. currency: 'GBP', // Always displays two digits after the decimal point. decimalPlaces: 2, // Adds thousands separators, for example £1,200.00. useGrouping: true, }, // Controls the visual styling of the formatted cell. appearance: { // Aligns the displayed value to the right of the cell. horizontal: 'right', },};
const euroWarningFormat: DataGridCellFormat = { value: { kind: 'preset', preset: 'accounting', locale: 'en-GB', currency: 'EUR', decimalPlaces: 2, }, appearance: { bold: true, textColor: '#b91c1c', fillColor: '#fef2f2', horizontal: 'right', },};
const columns: ColumnRegular<string, InvoiceRow>[] = [ { prop: 'customer', name: 'Customer' }, { prop: 'amount', name: 'Amount', // Called independently for every cell in this column. dataGridFormat: ({ model }) => model.amount < 0 ? euroWarningFormat : gbpFormat, },];
const source: InvoiceRow[] = [ { id: 'invoice-1', customer: 'Acme Ltd', amount: 1200 }, { id: 'invoice-2', customer: 'Northwind', amount: -350.5 },];
// Installs formatting, the Format Cells dialog, and its context-menu commands.grid.plugins = [DataGridFormattingPlugin];grid.columns = columns;grid.source = source;The resolver argument contains { model, value, prop, rowType }. Return a
DataGridCellFormat to format the cell, or undefined when the column does not
define a format for that cell. For one format across the entire column, assign
the object directly instead:
dataGridFormat: gbpFormat;When formatting is application state rather than column configuration, keep the same presets in the reactive grid property:
grid.dataGridFormatting = { columns: [{ column: 1, format: gbpFormat }], rows: [{ row: 0, format: { appearance: { bold: true } } }], cells: [{ range: { start: { row: 1, column: 1 } }, format: euroWarningFormat, }],};Coordinates are zero-based physical indexes in the row and column source
arrays. A row preset applies to every current and future column at that row
coordinate. A column preset applies to every current and future row at that
column coordinate. Presets use regular body sources by default. Set rowType
or colType when targeting a pinned source.
The declarative precedence is cell preset, then row preset, then grid column
preset, then column.dataGridFormat. Runtime operations through
DataGridFormattingPlugin.apply(), applyValueFormat(), or clear() take
precedence over every declarative source. The raw values remain 1200 and
-350.5 for editing, sorting, filtering, and application code.
Framework wrappers use the same grid property. In React and Vue, bind
dataGridFormatting directly. If a generated Angular wrapper version does not
yet declare that plugin property as an @Input, set
gridElement.dataGridFormatting = formattingState on the underlying
HTMLRevoGridElement. Do not put formatting state in additionalData; that
compatibility path is deprecated.
Format a whole column, whole row, or individual cells
Section titled “Format a whole column, whole row, or individual cells”The mutation API uses the same zero-based physical coordinates as declarative state. Complete-row and complete-column targets are explicit, so their intent is not lost when the grid currently has no rows or columns:
const formatting = (await grid .getPlugins()) .find(plugin => plugin instanceof DataGridFormattingPlugin);
if (!formatting) throw new Error('Formatting plugin is not installed.');
// The entire Amount column, including rows added later.formatting.apply( { scope: 'columns', ranges: { start: 1 } }, gbpFormat,);
// The entire first body row, including columns added later.formatting.apply( { scope: 'rows', ranges: { start: 0 } }, { appearance: { bold: true, fillColor: '#fef3c7' } },);
// One cell at physical row 1, physical column 1.formatting.apply( { start: { row: 1, column: 1 } }, euroWarningFormat,);end is inclusive and may be before start; the plugin normalizes reversed
ranges. Supply an array to format multiple independent ranges. Row targets may
set rowType, column targets may set colType, and cell ranges may set both.
The same targets work with applyValueFormat(), patch(), clear(),
openDialog(), and inferValueKind().
Enable Format Cells
Section titled “Enable Format Cells”Register the formatting plugin to make formatting available from cell and column-header menus. It installs the context-menu integration and dialog automatically:
import { DataGridFormattingPlugin } from '@revolist/revogrid-pro';
grid.plugins = [DataGridFormattingPlugin];The one-line formatting panel is installed with the formatting runtime but is disabled by default. Enable or disable it reactively with its dedicated grid property:
grid.dataGridFormattingPanel = true;
// Hide it again without removing the formatting plugin.grid.dataGridFormattingPanel = false;Assign a DataGridFormattingPanelConfig object instead of true when the
toolbar also needs localized labels.
Do not register DataGridContextMenuPlugin separately. If your grid already
uses it as its main menu plugin, keep that setup; it installs
DataGridFormattingPlugin in the opposite direction and reuses one instance of
each plugin.
Right-click a writable cell or column header and open Format. The submenu offers type-aware quick presets and two general actions:
- More formats… opens the complete Format Cells dialog.
- Clear formatting removes both value formatting and appearance formatting from the selected target.
For the complete context-menu configuration and command customization contract, see Data Grid Formatting.
Configure formatting defaults
Section titled “Configure formatting defaults”Formatting options belong under grid.dataGridContextMenu.formatting:
type InvoiceRow = { id: string; customer: string; amount: number; issuedAt: string;};
grid.dataGridContextMenu = { formatting: { autoAlignNumericValues: true, locale: 'en-GB', locales: ['en-GB', 'de-DE', 'fr-FR'], currencies: ['GBP', 'EUR', 'USD'], fontFamilies: ['Inter', 'Georgia', 'IBM Plex Mono'], columnTypeKinds: { money: 'number', applicationDate: 'date', }, resolveStructuralRowIdentity: (row) => row.id, },};| Option | Purpose |
|---|---|
autoAlignNumericValues | Right-aligns finite number and bigint values, plus Number, Currency, Accounting, Percentage, and Scientific formats, when horizontal alignment is Automatic. Effective advanced presentations keep their own layout. Defaults to true; set to false to disable this derived alignment. |
locale | Initial locale used by Intl.NumberFormat and Intl.DateTimeFormat. The browser locale is used when omitted. |
locales | Locale choices shown in the dialog. A built-in list is used when omitted. |
currencies | Currency choices shown by Currency and Accounting formats. The first entry is used by the dialog and quick presets. |
fontFamilies | Application font choices shown in Typography. |
columnTypeKinds | Maps application column types to number, date, text, boolean, mixed, or unknown for command availability. It does not convert values. |
resolveValueKind | Overrides value-kind inference for the complete selected target. It does not convert values. |
resolveStructuralRowIdentity | Retains formatting across length-changing immutable source updates by matching old and new row objects with an application-owned stable identity. Object identity is used when omitted. |
scopes | Limits formatting to cell, columnHeader, or both. |
advancedFormats | Configures compatible visual formats, individual format availability, custom definitions, and optional editor references. Set it to false to disable advanced formats. |
localeText | Replaces dialog, preset, option, palette, and advanced-format registry labels for localization. |
Physical coordinates and source replacement
Section titled “Physical coordinates and source replacement”Formatting belongs to a physical source position, not to a row object or business key:
grid.dataGridFormatting = { cells: [{ range: { start: { row: 1, column: 1 }, end: { row: 3, column: 2 }, }, format: euroWarningFormat, }],};
// New row objects at the same source positions receive the same formatting.grid.source = invoices.map((invoice) => ({ ...invoice }));Replacing every record without changing source length preserves formats at the
same coordinates. Structural source changes retain formats with surviving row
objects, remove formats owned by deleted rows, and shift or pin retained
formats with their rows. If an application recreates row objects while also
inserting or deleting records, configure resolveStructuralRowIdentity with a
stable unique business key so the old and new rows can be matched:
grid.dataGridContextMenu = { formatting: { resolveStructuralRowIdentity: (row) => row.id, },};Filtering only changes virtual order and does not change physical formatting addresses.
Accessibility and localization
Section titled “Accessibility and localization”Format Cells uses the shared modal focus trap and restores focus to the grid when it closes. Every native input and select has a programmatic label; icon-only actions expose a localized accessible name, pressed or expanded state, and a tooltip on both hover and keyboard focus. Escape dismisses an open control tooltip before a second Escape closes the dialog. Preset lists, segmented controls, color palettes, and expandable sections support their native or ARIA keyboard patterns, visible focus, forced-colors mode, and reduced motion preferences.
Dialog labels, actions, tooltips, validation feedback, the plain-text example,
and palette color names come from formatting.localeText. Section templates
replace {section} with the localized section name:
grid.dataGridContextMenu = { formatting: { localeText: { title: 'Formatear celdas', close: 'Cerrar formato de celdas', bold: 'Negrita', expandSection: 'Abrir {section}', collapseSection: 'Cerrar {section}', invalidColor: 'Introduce un color hexadecimal válido.', textExample: 'Ejemplo de texto', colorLabels: { '#be185d': 'Rosa', '#2563eb': 'Azul', }, advancedGroupLabels: { Indicators: 'Indicadores', }, advancedFormatLabels: { heatmap: 'Mapa térmico', }, advancedControlLabels: { 'heatmap.midValue': 'Punto medio', 'heatmap.highColor': 'Color alto', }, }, },};localeText is partial. Unspecified strings and palette names retain the
built-in English defaults. Every label map is merged by key, including
presetLabels, optionLabels, colorLabels, advancedGroupLabels,
advancedFormatLabels, advancedFormatDescriptions,
advancedControlLabels, and advancedOptionLabels.
Advanced controls use <format id>.<control key> keys. Select options append
the option value: <format id>.<control key>.<option value>. These same stable
keys localize application-defined formats; their registry-authored label or
description remains the fallback when a translation is omitted.
Set formatting: false to remove the formatting submenu while keeping the rest
of the context menu:
grid.dataGridContextMenu = { formatting: false,};This hides formatting commands; it does not remove declarative formats already
provided through dataGridFormat or dataGridFormatting.
Value formatting
Section titled “Value formatting”Value formats change only the string rendered in a cell. They do not replace the raw value used by editing, sorting, filtering, formulas, or application code.
The available presets are:
| Preset | Display behavior |
|---|---|
| Automatic | Leaves value display to the column’s existing renderer. |
| Number | Locale-aware numeric output with decimal and grouping controls. |
| Currency | Locale-aware currency output using the selected ISO currency. |
| Accounting | Currency output with accounting-style negative values. |
| Percentage | Locale-aware percentage output. With the default two decimal places, a raw value of 0.25 displays as 25.00% in en-US. |
| Scientific | Locale-aware scientific notation. |
| Date | Date output with short, medium, long, or full date style. |
| Time | Time output with short, medium, or long time style. |
| Date & time | Combined date and time output. |
| Plain text | Displays the value as text. |
Numeric formats support decimal places, thousands grouping, and negative-number styles. Currency formats also expose the configured currency list. Date and time formats support style controls and use the configured locale.
Quick menu commands are type-aware. Native JavaScript numbers and bigint
values expose numeric commands, while native Date values expose date and time
commands. Use columnTypeKinds or resolveValueKind to classify custom column
types and parseable date strings:
const issuedAtColumn = { prop: 'issuedAt', name: 'Issued', columnType: 'applicationDate',};
grid.columns = [ { prop: 'customer', name: 'Customer' }, { prop: 'amount', name: 'Amount', columnType: 'money' }, issuedAtColumn,];
grid.dataGridContextMenu = { formatting: { columnTypeKinds: { money: 'number', applicationDate: 'date', }, },};Type classification controls which quick commands are available; it does not
coerce the source value. Numeric presets format only number and bigint
values, so convert numeric strings to numbers before formatting them. Date
presets accept valid Date objects, parseable date strings, and non-negative
Excel serial-date numbers.
If a value cannot be converted by the selected formatter, the renderer falls back to the original value’s string representation instead of throwing.
Selecting preset: 'currency' is sufficient to activate the built-in
Intl.NumberFormat currency renderer. You do not install a separate currency
formatter. currency, locale, decimalPlaces, and useGrouping configure
that renderer.
Exact Excel-compatible format codes
Section titled “Exact Excel-compatible format codes”Choose Custom in Format Cells to edit an Excel-compatible number-format code with a live preview. Invalid codes disable Apply. The exact code is stored as a separate discriminated variant, so it cannot conflict with preset options:
const exactExcelFormat: DataGridCellFormat = { value: { kind: 'code', formatCode: '[Red][<0]#,##0.00;#,##0.00;"-";@', locale: 'en-GB', },};The internal formatter supports positive/negative/zero/text sections,
conditions and colors, locale/currency tokens, dates and elapsed time,
fractions, scientific notation, percentages, scaling, grouping, text
placeholders, quoted/escaped literals, and Excel spacing/fill instructions.
Raw source values are never replaced by their display text. Excel serial dates
use the shared dates module, including serial 60, while application Date
values remain Date values.
Advanced visual formats
Section titled “Advanced visual formats”Advanced format is a category in the existing Value formatting list. Select
it to reveal a grouped icon list of compatible visual formats and the options
declared by the selected format. Every row remains visible in the details pane;
built-ins use Font Awesome SVG icons, and custom definitions without an icon
receive the standard formatting icon. The category includes only formats
compatible with every non-null value in the current selection. Choosing one
stores only its stable ID and serializable options in
DataGridCellFormat.presentation; source values remain unchanged. The
appearance inspector stays available, so inherited text color, fill,
typography, alignment, and borders can still be adjusted.
You can predefine the same format on a column or choose it per cell:
const columns: ColumnRegular<string, ProjectRow>[] = [ { prop: 'completion', name: 'Completion', dataGridFormat: { presentation: { id: 'progress-line', options: { minValue: 0, maxValue: 100 }, }, }, }, { prop: 'metric', name: 'Metric', dataGridFormat: ({ model }) => model.metricKind === 'history' ? { presentation: { id: 'sparkline' } } : { presentation: { id: 'heatmap', options: { minValue: 0, maxValue: 100 }, }, }, },];Built-in formats and their required source shapes are:
| Value shape | Format IDs |
|---|---|
| Finite number | progress-line, progress-line-value, circular-progress, heatmap, rating, change, threshold |
| Boolean | boolean, thumbs |
| String, number, or boolean | badge, avatar, avatar-with-text |
| Non-empty number array | sparkline, bar, pie |
Non-empty { value, color?, name? }[] | pie |
Non-empty { start, end, label? }[] | timeline |
| Non-empty record of numeric values | summary-percentage, summary-aggregate |
The chart-only column-header renderer is not a cell format and is intentionally excluded. Mixed selections show a format only when every selected non-null value matches its shape.
When edited, Sparkline and Bar chart cells accept comma-separated numbers or a
JSON number array. Timeline opens as compact JSON and saves a validated
{ start, end, label? }[] value, so structured data never becomes
[object Object] or a display string.
The built-in boolean format displays Yes/No, while thumbs is its visual
alternative. Both open the same typed Yes/No/Not set dropdown on edit.
Their dropdown values and options reuse the active cell template, so switching
one cell between Boolean and Thumbs changes both its grid presentation and its
editor presentation without adding a column type.
Configure or disable formats
Section titled “Configure or disable formats”Compatible built-ins are enabled by default. Disable one format, change its application defaults, or disable the Advanced category under the context-menu formatting config:
grid.dataGridContextMenu = { formatting: { advancedFormats: { formats: { pie: false, heatmap: { defaults: { minValue: -20, maxValue: 50, colorMap: 'coldmap' }, }, }, }, },};
// Removes the Advanced category but keeps value and appearance formats.grid.dataGridContextMenu = { formatting: { advancedFormats: false },};Application-owned data such as badge styles, threshold definitions, dropdown
choices, and timeline bounds belongs in defaults or the column. The dialog
shows only controls declared by the format definition.
For the built-in Badge format, Fill color controls the badge background and
Text color controls the badge label. These colors do not paint the complete
cell. A matching badgeStyles entry supplies the fill fallback, while the label
inherits ordinary theme text until the user chooses an explicit Text color.
Register an application format
Section titled “Register an application format”Custom formats use the same registry and dialog controls as built-ins:
grid.dataGridContextMenu = { formatting: { advancedFormats: { customFormats: [ { id: 'risk-meter', label: 'Risk meter', group: 'Application', valueKind: 'number', defaults: { maximum: 10, color: '#dc2626' }, controls: [ { type: 'number', key: 'maximum', label: 'Maximum', min: 1 }, { type: 'color', key: 'color', label: 'Color' }, ], cellTemplate: (h, { value, column }) => h('meter', { min: 0, max: column.maximum, value, style: { accentColor: column.color }, }), }, ], }, },};Use isCompatible({ value, model, column, rowType }) instead of valueKind
when application data needs a more specific predicate.
Editors for formatted cells
Section titled “Editors for formatted cells”Formatting can select an editor for the actual cell being edited. The source
value preset can supply an editor, and an advanced-format definition can expose
its own editor reference. Editors remain optional dependencies supplied by
the application:
import DateColumnType from '@revolist/revogrid-column-date';import { badgeRenderer, ColumnDropdown } from '@revolist/revogrid-pro';
const dateType = new DateColumnType();
grid.dataGridContextMenu = { formatting: { advancedFormats: { presetEditors: { date: dateType.editor, datetime: dateType.editor, time: dateType.editor, }, customFormats: [ { id: 'status-badge', label: 'Status badge', valueKind: 'scalar', cellTemplate: badgeRenderer, editor: ColumnDropdown.editor, }, ], }, },};Editor resolution happens for each cell, so two cells in one column can use
different editors when dataGridFormat returns different value presets or
presentations. If a configured editor reference cannot be resolved, the plugin
uses the column’s original editor and then the grid’s text editor.
An application-authored editor is protected by default. Set
replaceAuthoredEditors: true only when formatted cells should take ownership
globally. Advanced presentation renderers also protect an authored
cellTemplate by default; configure replaceAuthoredTemplates globally or
replaceAuthoredTemplate on one definition when that advanced renderer should
replace it. Ordinary value categories are an explicit presentation choice: a
non-Automatic category replaces the authored visual template, while Automatic
restores it.
Appearance formatting
Section titled “Appearance formatting”Numeric cells use spreadsheet-style right alignment by default while the formatting plugin is installed. This applies to finite number and bigint source values even when they have no stored format, and to Number, Currency, Accounting, Percentage, and Scientific value formats. An explicit Left, Center, or Right appearance choice overrides the default. Advanced presentations such as Progress line and Rating stars retain their renderer-owned layout while alignment is Automatic; an explicit appearance alignment still overrides that layout.
To retain the grid’s existing alignment instead, disable automatic numeric alignment in the formatting configuration:
grid.dataGridContextMenu = { formatting: { autoAlignNumericValues: false, },};The appearance side of the dialog contains a live preview and these groups:
- Typography: font family, font size, bold, italic, underline, and strikethrough.
- Colors: text color and fill color, including predefined and custom colors.
- Alignment: horizontal alignment, vertical alignment, and text wrapping.
- Borders: border style and border color.
Appearance is composed with the column’s existing cellProperties. Apart from
the enabled-by-default numeric alignment described above, formatting adds or
overrides only explicitly selected style values, so unrelated authored classes
and styles remain in place.
Columns with an authored cellTemplate, including selection-style columns,
keep the complete Format Cells category list. Choosing a concrete value format
switches the cell to that plain value presentation; choosing Automatic restores
the authored template. Row-drag content remains appearance-only. For an
advanced format supplied declaratively or through the plugin API, set
replaceAuthoredTemplates globally, or replaceAuthoredTemplate on that
definition, only when its renderer should explicitly own those cells.
Copy and paste formatting
Section titled “Copy and paste formatting”DataGridFormattingPlugin installs one ClipboardPlugin automatically. The
formatting plugin remains the owner of the format throughout copy and paste:
- Copy asks the formatting runtime for the effective
DataGridCellFormatat every selected physical cell. - RevoGrid-to-RevoGrid copy stores that canonical format in the versioned rich clipboard payload, together with typed values, formulas, range geometry, merges, and explicit dimensions.
- Excel HTML import converts allowlisted Excel declarations into the same
DataGridCellFormatmodel. Clipboard code never installs raw Excel CSS on a cell. Excel CSS escapes and named formats such asShort Dateare normalized by the formatting plugin. - Paste sends values and formulas through the regular grid edit, readonly, and validation pipeline. Only accepted destinations receive formatting, applied as one formatting batch.
- Copy back to Excel converts the canonical format into Excel HTML declarations and number-format codes without changing the source row value.
This keeps formatting created at every supported scope in sync: individual cells, rectangular or independent ranges, complete rows, and complete columns. The effective resolved format is copied, including inherited row or column formatting; the destination receives a cell-level snapshot of that appearance.
Date handling follows the same non-destructive rule. Excel serial dates stay
typed numbers with a date/time format after import. When copying an application
Date or valid date-like value to Excel, only the outbound HTML representation
is converted to an Excel 1900-system serial. RevoGrid source data is not
rewritten.
Some Excel Desktop versions, including Excel for macOS, omit the typed x:num
attribute and expose only formatted display text. When that text is accompanied
by a recognized Accounting, Percentage, or date format, the formatting plugin
recovers the typed numeric or serial-date value before applying the canonical
format. It does not infer a type from unformatted visual text.
The same conversion covers the full Excel number-format family: Number, Currency, Accounting, Percentage, Fraction, Scientific, Date, Time, combined date-time, elapsed time, Special, and numeric/date/time Custom codes. General and Text remain text without an explicit typed clipboard value. Conditions, four-section positive/negative/zero/text rules, locale tokens, scaling commas, literal affixes, spacing, and fill are compiled by the same formatting engine used for cell rendering. See the display-only category matrix for the exact fallback policy.
The native Excel interoperability matrix shows the real Excel-to-RevoGrid rendering for the full tested number-format family and representative appearance options. The formats shown there are stored and rendered by this formatting plugin; clipboard code does not attach Excel CSS to cells.
For the exact directional support matrix, custom clipboard handlers, rich MIME contract, formulas, merges, dimensions, and the browser/native Excel boundary, see Smart Excel-Compatible Clipboard.
Range fill formatting
Section titled “Range fill formatting”DataGridFormattingPlugin also installs one AutoFillPlugin. Dragging the fill
handle stretches the source range’s effective formatting together with the value
sequence selected by AutoFill. A single Rating cell fills Rating cells; a two-row
or two-column source repeats its formats as a tile over the extended range.
Formatting remains owned by this plugin rather than being converted into cell CSS. The source format is resolved from the same cell, row, column, and authored-column precedence used during rendering. Destination formats are written as cell-level runtime operations in one batch after the range edit is accepted. A source slot with no effective format explicitly clears the corresponding destination slot, so old destination formatting does not leak into the filled result.
See the Autofill guide for value strategies, preview behavior, and range-fill setup.
Excel export
Section titled “Excel export”Add ExportExcelPlugin when Format Cells presentation should be retained in an
.xlsx workbook. The Excel plugin discovers the formatting runtime during
export:
import { DataGridFormattingPlugin, ExportExcelPlugin,} from '@revolist/revogrid-pro';
grid.plugins = [DataGridFormattingPlugin, ExportExcelPlugin];The integration exports the current formatting automatically:
- Number, Currency, Accounting, Percentage, Scientific, Date, Time, Date & time, and Plain text presets become native Excel number-format codes.
- Numeric and date cells remain typed workbook values rather than preformatted strings, so Excel formulas, editing, and sorting continue to work.
- Font family and size, emphasis, text and fill colors, alignment, wrapping, and borders become workbook cell styles.
- Group rows become merged, indented workbook headings. Export follows the visible grouped projection, so collapsed descendants are not included.
Advanced visual formats are not converted into Excel chart drawings. A format
definition can provide exportValue to convert its structured data to a
workbook-safe scalar while leaving the grid source unchanged. The built-in
Timeline format does this automatically: multiple events export as readable
text such as Build: 8–12; Review: 14–18 instead of [object Object].
Advanced formats without exportValue continue to export their raw cell value,
ordinary value format, and appearance.
Authored column.excelExport properties remain the base export configuration.
An explicitly selected Format Cells value or appearance setting overrides the
corresponding workbook field for that target without replacing unrelated
column-owned export properties.
Selection scope
Section titled “Selection scope”The menu surface decides which formatting scope is created:
- From a cell, formatting applies to the active writable range. If the multi-range plugin owns several selected ranges and the menu opens inside them, all resolved writable cells in those ranges are targeted.
- From a column header, formatting creates a column-wide default at the physical column address. It applies to body and pinned rows rendered for that column.
Readonly behavior is resolved before the command runs:
- Grid-level readonly mode prevents formatting changes.
- Readonly cells are skipped in mixed cell selections.
- A formatting command is unavailable when no writable target remains.
- Synthetic grouping rows are not assigned cell formatting.
Apply, Cancel, and Clear
Section titled “Apply, Cancel, and Clear”The dialog edits a temporary draft:
- Apply commits the complete value, advanced presentation, and appearance draft to the selected cells or columns, closes the dialog, and refreshes the grid.
- Cancel, the close button, backdrop dismissal, and Escape close the dialog without committing the draft.
- Clear formatting commits an explicit clear operation for the selected target and refreshes the grid.
Clear formatting does not clear the source value. It removes only the rendered format. An explicit clear also participates in cell-versus-column precedence, which is important when a cell override and a column default both exist.
Where formatting is stored
Section titled “Where formatting is stored”Formatting can come from declarative configuration or runtime operations:
column.dataGridFormatremains part of the column definition.grid.dataGridFormattingis application-owned grid state. Reassigning it replaces all declarative grid presets.- Formats created through the dialog or plugin API are held privately by the
current
DataGridFormattingPlugininstance; source rows are not modified.
The effective precedence is:
- A runtime format or explicit clear created through
apply(),applyValueFormat(),clear(), or the context menu. - A physical range preset in
grid.dataGridFormatting.cells. - A row preset in
grid.dataGridFormatting.rows. - A column preset in
grid.dataGridFormatting.columns. - The column’s static or function-based
dataGridFormat.
Within runtime state, each apply or clear operation receives a new revision. When matching runtime cell, row, and column operations overlap, the newest revision wins. For example:
- Format the
amountcolumn as Number. - Format one
amountcell as Currency; that newer cell override wins. - Clear the entire
amountcolumn; the newer column clear wins over the older cell override. - Format the individual cell again; the newest cell format wins.
A whole-row operation follows the same rule. It is stored once for the physical row, rather than expanded into the currently visible cells, so it also formats columns added later.
A DataGridCellFormat used by any of these sources has up to three independent
layers: ordinary value formatting, an advanced visual presentation, and
appearance. Omit any layer that the cell does not need:
const format = { value: { kind: 'preset', preset: 'currency', locale: 'en-GB', currency: 'GBP', decimalPlaces: 2, useGrouping: true, negativeStyle: 'minus', }, appearance: { bold: true, textColor: '#0f172a', fillColor: '#fef3c7', horizontal: 'right', wrap: false, borderStyle: 'solid', borderColor: '#f59e0b', }, presentation: { id: 'progress-line', options: { minValue: 0, maxValue: 100 }, },} as const;No format property is added to the example source row. Reading
row.amount still returns the original value.
How formatting reaches rendered cells
Section titled “How formatting reaches rendered cells”After Apply, Clear, or a grid.dataGridFormatting assignment, the plugin asks
RevoGrid to refresh all rendered cells. For each non-grouping cell, it resolves
the effective format during beforecellrender:
- Runtime and declarative sources are resolved using the precedence described above.
- Appearance settings are composed into
cellProperties. - A compatible advanced presentation renderer is supplied when one is
configured. An authored
cellTemplateor row-drag renderer remains protected unless replacement was explicitly enabled. - When there is no advanced renderer, a value-format renderer is supplied for a non-Automatic preset. This explicit choice replaces an authored visual template; Automatic leaves the authored template in place.
- The underlying row model and raw value remain unchanged.
Because lookup happens during rendering, formatting follows virtualization, scrolling, sorting, filtering, pinning, and ordinary grid refreshes. The plugin does not inspect rendered DOM to reconstruct state.
Save and restore formatting
Section titled “Save and restore formatting”Storage belongs to the application. After every runtime formatting change, the
plugin emits datagridformattingchange with the complete versioned state. Save
event.detail.state wherever the application already stores user preferences,
then pass it back through grid.dataGridFormatting.state when creating the
grid.
For example, use localStorage without adding storage behavior to the plugin:
const storageKey = 'invoice-grid-formatting';const savedState = localStorage.getItem(storageKey);
grid.plugins = [DataGridFormattingPlugin];grid.dataGridFormatting = { // Restore runtime formats once; omit state when nothing has been saved. state: savedState ? JSON.parse(savedState) : undefined,};
grid.addEventListener('datagridformattingchange', ({ detail }) => { // detail.state is the complete snapshot; no merge with older state is needed. localStorage.setItem(storageKey, JSON.stringify(detail.state));});The event fires after dialog Apply, Clear formatting, apply(),
applyValueFormat(), clear(), setState(), undo, and redo. Assigning
dataGridFormatting.state restores state without emitting another event, so it
does not create a save loop or a history entry.
Declarative columns, rows, and cells remain application defaults. The runtime
snapshot contains only user or API operations that override them, including
explicit clears and cell/row/column operation order. Source rows and raw values
remain unchanged.
Save to a server or application store
Section titled “Save to a server or application store”Load state first, assign it to the grid, and save the same complete event payload. Wrap it with your dataset version (or another stable layout token) so the server can reject stale coordinates:
const saved = await formattingApi.load(documentId);
grid.dataGridFormatting = { state: saved?.formatting,};
let documentVersion = saved?.version;let pendingSave = Promise.resolve();
grid.addEventListener('datagridformattingchange', ({ detail }) => { // Serialize writes so an older response cannot overwrite a newer edit. pendingSave = pendingSave.then(async () => { const result = await formattingApi.save(documentId, { version: documentVersion, datasetVersion: currentDatasetVersion, formatting: detail.state, }); documentVersion = result.version; });});detail.state is already a complete JSON-serializable snapshot: save it as a
replacement, not as a partial patch. On reload, restoring the snapshot does not
emit another persistence event. The application owns request batching,
authentication, retries, error messages, and conflict handling; the formatting
plugin only reports state changes.
Formatting addresses are physical indexes in the corresponding body or pinned
source arrays. They remain valid when row objects are replaced, edited, or
loaded again in the same order. If server sorting, filtering, pagination, or a
new dataset version changes that physical order, do not apply the old snapshot
blindly: reject it by datasetVersion, or migrate its coordinates before
assigning grid.dataGridFormatting.state. No row key callback is required or
consulted by the formatting runtime.
Undo and redo
Section titled “Undo and redo”Add History when formatting changes should use the same undo and redo stack as
data edits. DataGridFormattingPlugin installs Event Manager automatically:
import { DataGridFormattingPlugin, HistoryPlugin,} from '@revolist/revogrid-pro';
grid.plugins = [DataGridFormattingPlugin, HistoryPlugin];Each Apply or Clear operation is one history entry. Undo and redo restore the
complete previous or next formatting state and emit
datagridformattingchange, so the application saves the replayed state through
the same listener. No additional history configuration is required.
Manual state control
Section titled “Manual state control”The plugin instance also exposes getState() and setState():
const saved = formatting.getState();formatting.setState(saved);State version 2 includes runtime row, column, and physical-cell operations, explicit clears, dimension types, and revision order. It is JSON-safe when custom presentation options are JSON-safe.
Programmatic formatting API
Section titled “Programmatic formatting API”DataGridFormattingPlugin also provides methods for application-driven
formatting. It still installs the context menu and dialog; you only need to
retrieve the instance when application code must apply, inspect, clear, or open
formatting programmatically. Use the grid’s plugin collection rather than
attaching custom methods to the grid element:
import { DataGridFormattingPlugin, type DataGridFormattingSelection,} from '@revolist/revogrid-pro';
type InvoiceRow = { id: string; amount: number };
const invoice: InvoiceRow = { id: 'invoice-1', amount: 1200 };
grid.columns = [{ prop: 'amount', name: 'Amount' }];grid.plugins = [DataGridFormattingPlugin];grid.source = [invoice];
const formatting = (await grid.getPlugins()).find( (plugin) => plugin instanceof DataGridFormattingPlugin,) as DataGridFormattingPlugin<InvoiceRow> | undefined;
formatting?.configure({ locale: 'en-GB', currencies: ['GBP', 'EUR'],});
// Zero-based physical indexes into the rgRow and rgCol source arrays.const selection: DataGridFormattingSelection = { start: { row: 0, column: 0 },};
formatting?.apply(selection, { value: { kind: 'preset', preset: 'currency', locale: 'en-GB', currency: 'GBP', decimalPlaces: 2, }, appearance: { bold: true, horizontal: 'right', },});start identifies the first physical source cell. The optional inclusive
end defaults to start, so one coordinate formats one cell. rowType and
colType default to rgRow and rgCol.
// Entire physical row across four columns.formatting?.patch({ start: { row: 3, column: 0 }, end: { row: 3, column: 3 },}, { appearance: { bold: true },});
// Three rows by two columns.formatting?.apply({ start: { row: 3, column: 1 }, end: { row: 5, column: 2 },}, { appearance: { fillColor: '#fef3c7' },});
// Independent or overlapping ranges are accepted as an array.formatting?.clear([ { start: { row: 0, column: 0 }, end: { row: 1, column: 1 } }, { start: { row: 8, column: 4 } },]);Physical indexes address the unfiltered source arrays directly. Sorting,
filtering, and viewport order do not change which source models are targeted.
The plugin stores those coordinates directly and resolves the current source
row and column only when it needs rendering or callback context.
The public methods are:
| Method | Purpose |
|---|---|
configure(config) | Sets dialog and rendering options such as locale, currencies, fonts, and localized labels. |
apply(selection, format) | Replaces the selected target’s complete value, advanced presentation, and appearance format. |
applyValueFormat(selection, valueFormat) | Selects an ordinary value presentation, retains appearance, and replaces an active advanced visualization. |
clear(selection) | Applies an explicit clear that suppresses lower-priority declarative formats for the selected target. |
getFormat(address) | Resolves the effective format at a physical cell address. |
getColumnFormat(address) | Resolves the effective format for a complete physical column. |
getState() | Returns a portable, versioned snapshot of runtime Apply and Clear operations. |
setState(state) | Replaces runtime operations, refreshes the grid, and emits datagridformattingchange. |
openDialog(selection, valueKind, valueFormatting?) | Opens Format Cells for an application-provided selection. Pass false as the third argument for appearance-only editing. |
For example, open the same dialog programmatically:
formatting?.openDialog(selection, 'number');Or inspect and clear the known target:
const current = formatting?.getFormat({ row: 0, column: 0 });
if (current?.value?.preset === 'currency') { formatting?.clear(selection);}Practical recommendations
Section titled “Practical recommendations”- Use physical coordinates for persisted formatting. Replacing source objects at the same positions preserves formatting; moving records does not move it.
- Keep source values typed and unformatted; let the renderer own presentation.
- Use
columnTypeKindsto control type-aware command availability for custom column types and parseable date strings; it does not coerce numeric strings. - Use column-header formatting for broad defaults and cell formatting for exceptions.
- Choose Automatic to restore a custom interactive template after displaying a plain value format.
- Listen to
datagridformattingchangeand persistdetail.statein the application-owned browser store, state manager, or server API.