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. DataGridContextMenuPlugin installs that formatting
runtime automatically and supplies the selection opened from cell and column
header menus.
Enable Format Cells
Section titled “Enable Format Cells”Register the data-grid context menu to make formatting available from cell and column-header menus:
import { DataGridContextMenuPlugin } from '@revolist/revogrid-pro';
grid.plugins = [DataGridContextMenuPlugin];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 Context Menu & 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: { locale: 'en-GB', currencies: ['GBP', 'EUR', 'USD'], fontFamilies: ['Inter', 'Georgia', 'IBM Plex Mono'], getRowKey: (row: InvoiceRow) => row.id, columnTypeKinds: { money: 'number', applicationDate: 'date', }, },};| Option | Purpose |
|---|---|
locale | Initial locale used by Intl.NumberFormat and Intl.DateTimeFormat. |
currencies | Currency choices shown by Currency and Accounting formats. The first entry is the dialog default. |
fontFamilies | Application font choices shown in Typography. |
getRowKey | Gives cell formatting stable row identity when source row objects are replaced. |
columnTypeKinds | Maps application column types to number, date, text, boolean, mixed, or unknown. |
resolveValueKind | Overrides value-kind inference for the complete selected target. |
scopes | Limits formatting to cell, columnHeader, or both. |
localeText | Replaces dialog labels, preset labels, and option labels for localization. |
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.
All dialog copy comes from formatting.localeText, including tooltip actions,
validation feedback, the plain-text example, and palette color names. 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', }, }, },};localeText is partial. Unspecified strings and palette names retain the
built-in English defaults, while presetLabels, optionLabels, and
colorLabels are merged by key.
Set formatting: false to remove the formatting submenu while keeping the rest
of the context menu:
grid.dataGridContextMenu = { formatting: false,};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 | Uses the raw value’s normal string representation. |
| 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. A raw value of 0.25 displays as 25%. |
| 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 when an application stores
typed values as strings or uses custom column types:
const issuedAtColumn = { prop: 'issuedAt', name: 'Issued', columnType: 'applicationDate',};
grid.columns = [ { prop: 'customer', name: 'Customer' }, { prop: 'amount', name: 'Amount', columnType: 'money' }, issuedAtColumn,];
grid.dataGridContextMenu = { formatting: { getRowKey: (row: InvoiceRow) => row.id, columnTypeKinds: { money: 'number', applicationDate: 'date', }, },};If a value cannot be converted by the selected formatter, the renderer falls back to the original value’s string representation instead of throwing.
Appearance formatting
Section titled “Appearance formatting”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. Formatting
adds or overrides only explicitly selected style values, so unrelated authored
classes and styles remain in place.
Columns with an authored cellTemplate or row-drag content keep that template.
For context-menu selections that include such columns, the dialog opens in
appearance-only mode because replacing the display value could remove
interactive content. Typography, color, alignment, wrapping, and borders remain
available.
Excel export
Section titled “Excel export”Add ExportExcelPlugin when Format Cells presentation should be retained in an
.xlsx workbook. DataGridContextMenuPlugin already installs the formatting
runtime, and the Excel plugin discovers that runtime during export:
import { DataGridContextMenuPlugin, ExportExcelPlugin,} from '@revolist/revogrid-pro';
grid.plugins = [DataGridContextMenuPlugin, 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.
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 keyed by the column property. 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 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”DataGridFormattingPlugin owns formatting state independently of RevoGrid’s
row source and column definitions:
- Column defaults are identified by column property.
- Cell overrides are identified by a row and column property.
- Each apply or clear operation receives a new revision.
- When both a column default and a cell override match, the newer revision wins.
This revision rule makes later operations predictable. 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.
The stored format is a DataGridCellFormat with two independent layers:
const format = { value: { 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', },} as const;No format property is added to the example source row. Reading
row.amount still returns the original value.
Row identity and immutable data
Section titled “Row identity and immutable data”By default, a cell format is associated with the exact source row object. This works when the same row objects remain in the source through sorting, filtering, and normal rerenders:
const row = { id: 'invoice-1', amount: 1200 };grid.source = [row];
// Reusing `row` keeps the default object identity.grid.source = [row];Replacing rows with new objects changes that identity. Configure getRowKey
for immutable updates, server refreshes, and state-library projections:
grid.dataGridContextMenu = { formatting: { getRowKey: (row: InvoiceRow) => row.id, },};
grid.source = rows.map(row => ({ ...row, customer: row.customer.trim() }));With getRowKey, a replacement row receives the existing format when it has
the same key in the same row dimension. Pinned-top, regular, and pinned-bottom
row dimensions are kept separate, so the same application key can be formatted
differently in each dimension.
Row keys must be stable and unique inside each row dimension. Changing a key makes the row a different formatting target. Reusing one key for multiple rows causes those rows to share cell-format identity for the same column.
How formatting reaches rendered cells
Section titled “How formatting reaches rendered cells”After Apply or Clear, the plugin asks RevoGrid to refresh all rendered cells.
For each regular cell, it resolves the newest matching cell or column format
during beforecellrender:
- Appearance settings are composed into
cellProperties. - A value-format renderer is supplied when a non-Automatic preset can safely own display output.
- 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.
Runtime lifetime and persistence
Section titled “Runtime lifetime and persistence”Formatting state survives grid rerenders and source replacement when stable row keys are configured. It does not survive destruction of the formatting plugin, destruction of the grid, navigation, or a page reload.
The current public contract does not provide a bulk persistence export/import
API for all stored formats. ExportExcelPlugin can transfer current formats to
a workbook, and getFormat() can inspect a known row/column target, but neither
API enumerates a reusable formatting-state document. If formatting must be
saved to a backend or browser storage, keep an application-owned formatting
model and reapply it when the grid is created.
Use the formatting plugin directly
Section titled “Use the formatting plugin directly”Applications can register DataGridFormattingPlugin without the universal
context menu and call its public methods. Retrieve the plugin instance through
the grid’s plugin collection rather than attaching custom methods to the grid
element:
import type { ColumnRegular } from '@revolist/revogrid';import { DataGridFormattingPlugin, type DataGridFormattingSelection,} from '@revolist/revogrid-pro';
type InvoiceRow = { id: string; amount: number };
const amountColumn: ColumnRegular = { prop: 'amount', name: 'Amount',};const invoice: InvoiceRow = { id: 'invoice-1', amount: 1200 };
grid.columns = [amountColumn];grid.plugins = [DataGridFormattingPlugin];grid.source = [invoice];
const formatting = (await grid.getPlugins()).find( plugin => plugin instanceof DataGridFormattingPlugin,) as DataGridFormattingPlugin<InvoiceRow> | undefined;
formatting?.configure({ getRowKey: row => row.id, locale: 'en-GB', currencies: ['GBP', 'EUR'],});
const selection: DataGridFormattingSelection<InvoiceRow> = { scope: 'cells', columns: [amountColumn], rows: [invoice], cells: [{ model: invoice, column: amountColumn, rowType: 'rgRow', }],};
formatting?.apply(selection, { value: { preset: 'currency', locale: 'en-GB', currency: 'GBP', decimalPlaces: 2, }, appearance: { bold: true, horizontal: 'right', },});The public methods are:
| Method | Purpose |
|---|---|
configure(config) | Sets locale, identity, type inference, scope, and dialog options. |
apply(selection, format) | Replaces the selected target’s complete value and appearance format. |
applyValueFormat(selection, valueFormat) | Replaces only the value-format layer and retains appearance. |
clear(selection) | Applies an explicit clear operation to the selected target. |
getFormat(model, prop, rowType?) | Resolves the currently effective format for a known cell or column. |
openDialog(selection, valueKind, valueFormatting?) | Opens Format Cells for an application-provided selection. |
For example, open the same dialog programmatically:
formatting?.openDialog(selection, 'number');Or inspect and clear the known target:
const current = formatting?.getFormat(invoice, 'amount', 'rgRow');
if (current?.value?.preset === 'currency') { formatting?.clear(selection);}Practical recommendations
Section titled “Practical recommendations”- Configure
getRowKeyfor any application that replaces row objects. - Keep source values typed and unformatted; let the renderer own presentation.
- Use
columnTypeKindswhen application date or numeric values are stored as strings. - Use column-header formatting for broad defaults and cell formatting for exceptions.
- Preserve custom interactive templates by using appearance-only formatting.
- Keep an application-owned format model when formats must survive reloads or be synchronized with a server.