Skip to content

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.

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.

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',
},
},
};
OptionPurpose
localeInitial locale used by Intl.NumberFormat and Intl.DateTimeFormat.
currenciesCurrency choices shown by Currency and Accounting formats. The first entry is the dialog default.
fontFamiliesApplication font choices shown in Typography.
getRowKeyGives cell formatting stable row identity when source row objects are replaced.
columnTypeKindsMaps application column types to number, date, text, boolean, mixed, or unknown.
resolveValueKindOverrides value-kind inference for the complete selected target.
scopesLimits formatting to cell, columnHeader, or both.
localeTextReplaces dialog labels, preset labels, and option labels for 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 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:

PresetDisplay behavior
AutomaticUses the raw value’s normal string representation.
NumberLocale-aware numeric output with decimal and grouping controls.
CurrencyLocale-aware currency output using the selected ISO currency.
AccountingCurrency output with accounting-style negative values.
PercentageLocale-aware percentage output. A raw value of 0.25 displays as 25%.
ScientificLocale-aware scientific notation.
DateDate output with short, medium, long, or full date style.
TimeTime output with short, medium, or long time style.
Date & timeCombined date and time output.
Plain textDisplays 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.

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.

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.

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.

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.

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:

  1. Format the amount column as Number.
  2. Format one amount cell as Currency; that newer cell override wins.
  3. Clear the entire amount column; the newer column clear wins over the older cell override.
  4. 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.

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.

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:

  1. Appearance settings are composed into cellProperties.
  2. A value-format renderer is supplied when a non-Automatic preset can safely own display output.
  3. 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.

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.

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:

MethodPurpose
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);
}
  • Configure getRowKey for any application that replaces row objects.
  • Keep source values typed and unformatted; let the renderer own presentation.
  • Use columnTypeKinds when 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.