Parsing and Formatting
This page explains how developers can use FormatterSpec and ParserSpec to format quantity values and parse user input strings. It also covers integration with iTwin tools and components.
FormatterSpec and ParserSpec
FormatterSpec
FormatterSpec is the runtime object used to format numeric quantity values into display strings. It contains:
- The Format specification defining display rules
- Cached UnitConversionSpec objects for all display units
- The persistence unit (source unit for the value)
Creating a FormatterSpec:
Using a FormatterSpec:
ParserSpec
ParserSpec is the runtime object used to parse formatted strings back into numeric values. It contains:
- The Format specification for recognizing unit labels
- Cached UnitConversionSpec objects for all units in the phenomenon
- The persistence unit (target unit for parsed values)
Simple Code Examples
Numeric Formatting Example
This example uses a simple numeric format with 4 decimal place precision:
Example Code
Composite Formatting Example
This example formats a metric value (meters) as feet-inches with fractional precision:
Example Code
Parser Behavior
The Parser converts text strings into numeric quantity values by tokenizing the input and matching unit labels to known units. Understanding parser behavior helps you handle edge cases and errors correctly.
Parsing Process
Tokenization: The input string is broken down into tokens representing numbers, unit labels, and mathematical operators (if enabled).
Unit Label Matching: For each unit label token found, the parser attempts to match it against:
- Units explicitly defined in the format specification
- Units from the same phenomenon (unit family) provided by the UnitsProvider
- Alternate labels defined through the AlternateUnitLabelsProvider
Error Handling: The parser's behavior when encountering unrecognized unit labels depends on the format configuration:
- Unitless Format (no units defined in format definition): If a unit label is provided but cannot be matched to any known unit, the parser returns
ParseError.UnitLabelSuppliedButNotMatched. This prevents silent failures where typos like "12 im" (instead of "12 in") would incorrectly parse as "12 meters" when the persistence unit is meters. - Format with Units (units explicitly defined): If an unrecognized unit label is provided (e.g., "12 ABCDEF"), the parser falls back to the format's default unit for backward compatibility. For example, with a feet format, "12 ABCDEF" would parse as "12 feet".
- Unitless Format (no units defined in format definition): If a unit label is provided but cannot be matched to any known unit, the parser returns
Default Unit Behavior: If no unit label is provided in the input (e.g., just "12"), the parser uses the default unit specified in the format. For unitless formats, if the input contains multiple unit labels, the first successfully matched unit becomes the default for subsequent unitless values in the same expression.
Unit Conversion: Once units are matched, the parser applies the appropriate unit conversions to produce a value in the persistence unit specified by the
ParserSpec.
Example: Parsing Values
Basic parsing example
Mathematical Operations
The quantity formatter supports parsing mathematical operations, allowing users to enter expressions like "5 ft + 12 in - 6 in". The parser evaluates the expression and formats each value according to the specified format.
Enabling Mathematical Operations
Mathematical operations are disabled by default. To enable them, set the allowMathematicOperations property in your format:
Enabling mathematical operations
Example: Parsing Mathematical Expressions
Parsing mathematical operations
Limitations
Only plus (+) and minus (-) operators are currently supported. Other operators will return a parsing error or invalid input result.
Whitespace Handling
If a format uses a spacer that conflicts with the operators above, additional restrictions apply:
- Mathematical operations are recognized when whitespace follows the operator. For example:
-2FT 6IN + 6INis parsed the same as-2FT-6IN + 6IN, both resulting in -2 feet-2FT-6IN - 6INis parsed the same as-2FT-6IN- 6IN, both resulting in -3 feet
Whitespace limitation example
Composite Unit Handling
- For a value like
2FT 6IN-0.5, the-is treated as the composite spacer (not subtraction) when the format's spacer is-. The trailing0.5is parsed as an additional unitless value, so it uses the default unit conversion (the first composite unit,FT). In effect,2FT 6IN-0.5is parsed the same as2FT 6IN 0.5, which is equivalent to2FT 6IN + 0.5FT.
Composite unit limitation example
Usage in iTwin Tools and Components
This section explains how iTwin tools and components integrate FormatterSpec and ParserSpec for consistent quantity formatting and parsing.
QuantityFormatter Integration
The QuantityFormatter class in @itwin/core-frontend provides a convenient interface for formatting and parsing quantities. It manages:
- Default formats for each QuantityType, but there's an effort to move away from using
QuantityType. See Migrating from QuantityType to KindOfQuantity - Format overrides through UnitFormattingSettingsProvider
- Unit system management (metric, imperial, usCustomary, usSurvey)
- UnitsProvider registration
The QuantityFormatter is automatically initialized when IModelApp starts, creating cached FormatterSpec and ParserSpec objects for each QuantityType.
Measure Tools Examples (Outdated)
iTwin.js includes several measure tools that use QuantityFormatter to display formatted values and parse user input. Below are two representative examples showing the general pattern.
These examples are retained from older, outdated documentation that use QuantityType. We recommend following the General Pattern for Tools and Components section, and see an explanation on moving away from QuantityType below.
Example 1: MeasureDistanceTool - Formatting
The MeasureDistanceTool formats distance values for display:
MeasureDistanceTool formatting example
Typical format behavior:
Imperial: Displays as
X'-X"with inches to nearest 1/8"{ "composite": { "units": [{ "label": "'", "name": "Units.FT" }, { "label": "\"", "name": "Units.IN" }] }, "precision": 8, "type": "Fractional" }Metric: Displays as
Xmwith 4 decimal places{ "composite": { "units": [{ "label": "m", "name": "Units.M" }] }, "precision": 4, "type": "Decimal" }
Example 2: MeasureLocationTool - Parsing
The MeasureLocationTool parses user-entered angle strings:
MeasureLocationTool parsing example
Typical parsing behavior:
The parser accepts various angle formats:
24^34.5'- Using alternate label "^" for degrees24°34.5'- Using standard degree symbol45.5°- Decimal degrees45°30'15"- Degrees, minutes, seconds
The ParserSpec for angles includes conversions from all angular units (degrees, minutes, seconds, gradians) to the persistence unit (radians).
General Pattern for Tools and Components
When developing tools or components that format/parse quantities:
Identify the KindOfQuantity: Determine which KindOfQuantity your tool should use (e.g.,
DefaultToolsUnits.LENGTH,CivilUnits.STATION)Get FormatProps: Retrieve the format from the active FormatsProvider. If not found, provide a fallback format definition.
await IModelApp.quantityFormatter.setActiveUnitSystem("metric"); // When the default formats provider is used, ensure the desired unit system is active let formatProps = await IModelApp.formatsProvider.getFormat("DefaultToolsUnits.LENGTH"); if (!formatProps) { // Fallback: Define a hardcoded format for your tool formatProps = { composite: { units: [{ label: "m", name: "Units.M" }] }, precision: 1, type: "Decimal" }; }Convert to Format and Get Persistence Unit: Create a Format object from FormatProps and retrieve the persistence unit. Access the UnitsProvider from IModelApp.
const unitsProvider = IModelApp.quantityFormatter.unitsProvider; const format = new Format("length"); await format.fromJSON(unitsProvider, formatProps); const persistenceUnit = await unitsProvider.findUnitByName("Units.M");Create Specs: Create FormatterSpec and ParserSpec as needed
const formatterSpec = await FormatterSpec.create("length", format, unitsProvider, persistenceUnit); const parserSpec = await ParserSpec.create(format, unitsProvider, persistenceUnit);Format/Parse: Use the specs throughout your tool's lifecycle
const value = 5.5; const userInput = "10.5 m"; const formatted = formatterSpec.applyFormatting(value); // "5.5000 m" const parsed = parserSpec.parseToQuantityValue(userInput); // 10.5
Migrating from QuantityType to KindOfQuantity
Starting in iTwin.js 5.0, we encourage developers to move away from using QuantityType and instead use KindOfQuantity EC full names.
Why Migrate?
- Broader range of formatting capabilities: Not limited to nine built-in types
- Dynamic format definition: Work with formats defined in custom schemas
- Scalability: Use MutableFormatsProvider to add or override formats
- Schema integration: Better alignment with BIS schemas and domain models
QuantityType Replacement Table
| QuantityType | Actual KindOfQuantity (EC Full Name) |
|---|---|
| Length | DefaultToolsUnits.LENGTH |
| Angle | DefaultToolsUnits.ANGLE |
| Area | DefaultToolsUnits.AREA |
| Volume | DefaultToolsUnits.VOLUME |
| LatLong | DefaultToolsUnits.ANGLE |
| Coordinate | DefaultToolsUnits.LENGTH_COORDINATE |
| Stationing | CivilUnits.STATION |
| LengthSurvey | CivilUnits.LENGTH |
| LengthEngineering | AecUnits.LENGTH |
Schema Layers:
- DefaultToolsUnits - Common layer schema present in many iModels
- CivilUnits - Discipline-Physical layer for civil infrastructure
- AecUnits - Common layer for AEC applications
More information on schemas and their different layers can be found in BIS Organization.
Handling Missing Schemas
iModels might not include CivilUnits, DefaultToolsUnits, or AecUnits schemas. In such cases:
- Integrate your tools/components to use a
FormatsProviderseparate fromIModelApp.formatsProvider - Add the missing KindOfQuantity and associated FormatProps through that FormatsProvider
- This works independently from schemas in iModels
Alternatively, a fallback, hardcoded FormatProps that your tool can rely on would suffice.
Default Support
To support migration, IModelApp uses an internal QuantityTypeFormatsProvider by default, which provides formatProps for each KindOfQuantity in the table above. We still strongly encourage developers to either implement their own FormatsProvider or use SchemaFormatsProvider if possible.
Note: We plan to deprecate
QuantityTypeduring the iTwin.js 5.x lifecycle.
Ratio Formatting and Parsing
Ratio formats enable the display of proportional relationships between quantities, commonly used for scale factors, slopes, and architectural drawings. For detailed information about ratio format properties and configuration, see Ratio Format Properties.
Metric Scale Ratio Formatting
The example below demonstrates formatting metric scale ratios commonly used in architectural and engineering drawings. The format uses OneToN ratio type to display scales like 1:100 or 1:50.
Example Code
Imperial Scale Ratio Formatting
The example below demonstrates formatting imperial architectural scales with fractional notation. The format uses NToOne ratio type with fractional formatting to display scales like 1/4"=1' (quarter-inch scale) or "3/4"=1'" (three-quarter-inch scale).
Example Code
Metric Scale Ratio Parsing
The example below demonstrates parsing metric scale ratios. The parser can handle standard ratio notation like 1:100 or 1:50 and convert them to decimal length ratio values.
Example Code
Imperial Scale Ratio Parsing
The example below demonstrates parsing imperial architectural scales with fractional notation. The parser can handle fractional values like 1/4"=1', mixed fractions like 1 1/2"=1', and decimal values, converting them to decimal length ratio values.
Example Code
See Also
- Formats - Format specification reference
- Ratio Format Properties - Detailed ratio format configuration
- Providers - Setting up UnitsProvider and FormatsProvider
- Unit Conversion - How unit conversions work
Last Updated: 02 February, 2026