src/platform/plugins/shared/field_formats/README.md
The Field Formats plugin provides a service for formatting field values in Kibana. It's used by data views (index patterns) and throughout the application to consistently format data for display.
Field formatters use a React-first architecture:
User Data → Field Formatter → {text|react} → Consumer Component
↓
React Elements (Safe)
↓
Direct React Rendering
The FieldFormat base class exposes two public methods that consumers call:
convertToText(value, options) — returns a plain string. Handles arrays automatically (JSON-encodes them), then delegates to the protected textConvert hook for scalar values.convertToReact(value, options) — returns a ReactNode. Handles arrays, missing values, and search-term highlighting automatically, then delegates to the protected reactConvert hook for scalar values.Subclasses customize behaviour by overriding two protected hooks:
textConvert — scalar-value text conversion.reactConvert — scalar-value React conversion. When omitted, convertToReact falls back to textConvert output with automatic highlight wrapping. ┌──────────────────────────┐
Consumer calls: │ convertToText(value) │ public
│ convertToReact(value) │ public
└────────────┬─────────────┘
│ delegates (after array/missing/highlight handling)
┌────────────▼─────────────┐
Subclass overrides: │ textConvert(value) │ protected
│ reactConvert(value) │ protected
└──────────────────────────┘
Do not call
textConvertorreactConvertfrom outside aFieldFormatsubclass. They areprotectedand not part of the public API.
import { formatFieldValueReact } from '@kbn/discover-utils';
// Using the utility function
const reactNode = formatFieldValueReact({ value, hit, fieldFormats, dataView, field });
// Render directly in your component
return <div className="my-cell">{reactNode}</div>;
// Get a formatter instance from the registry
const formatter = fieldFormats.getDefaultInstance(KBN_FIELD_TYPES.NUMBER);
// Plain text
const text: string = formatter.convertToText(42);
// React node (handles highlighting, missing values, arrays)
const node: ReactNode = formatter.convertToReact(42, { field: { name: 'price' }, hit });
At minimum, override textConvert. Add reactConvert when you need custom React rendering (colors, links, styled elements, etc.).
import { FieldFormat } from '@kbn/field-formats-plugin/common';
import type { TextContextTypeConvert } from '@kbn/field-formats-plugin/common';
export class MyFormat extends FieldFormat {
static id = 'my_format';
static title = 'My Format';
static fieldType = ['string', 'number'];
textConvert: TextContextTypeConvert = (value) => {
return `Formatted: ${value}`;
};
}
The base class will use textConvert output for both convertToText() and convertToReact(), automatically adding highlight <mark> wrapping and missing-value labels in React mode.
import { FieldFormat } from '@kbn/field-formats-plugin/common';
import type { ReactConvertFunction, TextContextTypeConvert } from '@kbn/field-formats-plugin/common';
export class ColoredFormat extends FieldFormat {
static id = 'colored';
static title = 'Colored';
static fieldType = ['string', 'number'];
textConvert: TextContextTypeConvert = (value) => {
return String(value);
};
reactConvert: ReactConvertFunction = (value) => {
// Handle missing values
const missing = this.checkForMissingValueReact(value);
if (missing) return missing;
return <span style={{ color: 'blue' }}>{String(value)}</span>;
};
}
When you override
reactConvert, you take responsibility for missing-value handling and highlighting. Callthis.checkForMissingValueReact(value)at the top.
// Public plugin
export class MyPlugin implements Plugin {
setup(core, { fieldFormats }) {
fieldFormats.register([MyFormat]);
}
}
// Server plugin
export class MyServerPlugin implements Plugin {
setup(core, { fieldFormats }) {
fieldFormats.register(MyFormat);
}
}
textConvert for plain text output.reactConvert only when you need custom React elements (styled output, links, etc.). The base class provides sensible React rendering from textConvert alone.checkForMissingValueText() / checkForMissingValueReact() in your overrides.convertToText or convertToReact — override the protected hooks instead so array handling is always applied correctly.this.param('name') to access user-configurable parameters, and override getParamDefaults() to set defaults./common/converters/)BoolFormat - Boolean values (true/false)BytesFormat - File sizes (1KB, 1MB, etc.)ColorFormat - Values with background/text colors based on rulesCurrencyFormat - Monetary values with currency symbolsDurationFormat - Time durations (ms, seconds, minutes, etc.)GeoPointFormat - Geographic coordinatesHistogramFormat - Histogram data structuresIpFormat - IP addressesNumberFormat - Numeric values with locale formattingNumeralFormat - Base class for numeric formattersPercentFormat - Percentage valuesRelativeDateFormat - Relative time ("2 hours ago", "in 3 days")SourceFormat - Raw JSON source documentsStaticLookupFormat - Value mapping/lookup tablesStringFormat - String values with optional transformationsTruncateFormat - String truncation with ellipsisUrlFormat - URLs rendered as links, images, or audio/public/lib/converters/)DateFormat - Date/time formatting with timezone supportDateNanosFormat - High-precision nanosecond dates/server/lib/converters/)DateFormat (server version) - Server-side date formattingDateNanosFormat (server version) - Server-side nanosecond datesSuffixFormatter (x-pack/platform/plugins/shared/lens/common/suffix_formatter/)ExampleCurrencyFormat (examples/field_formats_example/common/)The React-first architecture eliminates XSS vulnerabilities by:
<mark> elements instead of raw HTML injection