---
title: "useFormatter"
description: "Composable that returns shared `FormatterNumbers` and `FormatterIban` instances pre-configured with country specifications."
canonical_url: "https://bitrix24.github.io/b24jssdk/docs/working-with-the-rest-api/tools-use-formatters"
last_updated: "2026-07-01"
---
# useFormatter

> Composable that returns shared `FormatterNumbers` and `FormatterIban` instances pre-configured with country specifications.

## Overview

`useFormatter()`{className="language-ts-type shiki shiki-themes material-theme-lighter material-theme material-theme-palenight" language="ts-type" style=""} is a composable exported from `@bitrix24/b24jssdk`. It returns two shared, singleton formatters:

- **`formatterNumber`** — a `FormatterNumbers` instance, a locale-aware wrapper around `Intl.NumberFormat`.
- **`formatterIban`** — a `FormatterIban` instance, pre-loaded with IBAN country specifications: every country from the official IBAN registry, several non-official countries that follow the IBAN structure, and the French regional/administrative subdivisions (GF, GP, MQ, RE, PF, TF, YT, NC, BL, MF, PM).

Both formatters are singletons (`FormatterNumbers.getInstance()` / `FormatterIban.getInstance()`), so every call to `useFormatter()` returns the same underlying instances — state set on one (e.g. a default locale) is visible everywhere else in the app. `useFormatter()` re-registers the IBAN specifications on every call, but since `formatterIban` is a singleton and `addSpecification` just overwrites the map entry for a country code, calling `useFormatter()` repeatedly is cheap.

```ts
import { useFormatter } from '@bitrix24/b24jssdk'

const { formatterNumber, formatterIban } = useFormatter()

console.log(formatterIban.printFormat('GB29NWBK60161331926819'))
// 'GB29 NWBK 6016 1331 9268 19'

console.log(formatterIban.isValid('DE89370400440532013000'))
// true

console.log(formatterNumber.format(1234.567))
// '1,234.57'
```

## Method Signature

### `useFormatter()`

```ts-type
useFormatter(): {
  formatterNumber: FormatterNumbers
  formatterIban: FormatterIban
}
```

### `FormatterNumbers`

```ts-type
setDefLocale(locale: string): void
format(value: number, locale?: string): string
```

### `FormatterIban`

```ts-type
addSpecification(spec: IbanSpecification): void

isValid(iban: string): boolean
printFormat(iban: string, separator?: string): string     // default separator ' '
electronicFormat(iban: string): string                     // strips non-alphanumerics, uppercases

toBBAN(iban: string, separator?: string): string           // default separator ' '
fromBBAN(countryCode: string, bban: string): string
isValidBBAN(countryCode: string, bban: string): boolean
```

## Key Concepts

> [!NOTE]
> `FormatterNumbers.format` picks a locale in this order: the explicit `locale` argument, then the locale set via `setDefLocale`, then `navigator.language` (browser only), then falls back to `'en'`. Integers are formatted with 0 decimal places, non-integers with exactly 2. When the resolved locale contains `'ru'`, the decimal comma produced by `Intl.NumberFormat` is replaced with a dot.

> [!NOTE]
> `FormatterIban.isValid` and the BBAN methods (`toBBAN`, `fromBBAN`, `isValidBBAN`) throw `Error('No country with code XX')` if the IBAN's/BBAN's country code has no registered `IbanSpecification`. Since `useFormatter()` already registers every supported country, this only happens for genuinely unsupported or malformed country codes.

- **`isValid` accepts loosely formatted input.** It runs the IBAN through `electronicFormat` first, so spaces and lower-case letters are normalised before the country-specific length, structure, and ISO 7064 MOD 97-10 checksum are verified. Non-string input returns `false` instead of throwing.
- **`printFormat` and `toBBAN` both normalise with `electronicFormat` first**, so they accept the same loosely formatted input as `isValid`.
- **`addSpecification` overwrites by country code.** Calling it again for a country already registered (as `useFormatter()` does on every call) simply replaces the existing `IbanSpecification` — it is not cumulative and cannot throw.
- **`FormatterNumbers` and `FormatterIban` are not constructable directly.** Both classes guard their constructor and only `getInstance()` can create the singleton; always obtain them through `useFormatter()`.

## Error Handling

`useFormatter()` itself never throws. `FormatterIban.isValid` returns `false` for malformed or non-string input rather than throwing. The BBAN helpers (`toBBAN`, `fromBBAN`, `isValidBBAN`) and the checksum path throw `Error('No country with code XX')` only for a country code that has no registered `IbanSpecification` — which `useFormatter()` never produces, since it registers every supported country on each call. `FormatterNumbers` delegates to `Intl.NumberFormat`, which throws `RangeError` for an invalid locale or option, not for numeric input.

## Examples

Validating and formatting an IBAN:

```ts
import { useFormatter } from '@bitrix24/b24jssdk'

const { formatterIban } = useFormatter()

formatterIban.isValid('DE89370400440532013000') // true
formatterIban.isValid('GB29NWBK60161331926818') // false (bad checksum)

formatterIban.printFormat('GB29NWBK60161331926819') // 'GB29 NWBK 6016 1331 9268 19'
formatterIban.printFormat('GB29NWBK60161331926819', '-') // 'GB29-NWBK-6016-1331-9268-19'

// Accepts loosely formatted input (spaces, lower case)
formatterIban.electronicFormat('GB29 NWBK 6016 1331 9268 19') // 'GB29NWBK60161331926819'
```

Converting between IBAN and BBAN:

```ts
import { useFormatter } from '@bitrix24/b24jssdk'

const { formatterIban } = useFormatter()

formatterIban.toBBAN('GB29NWBK60161331926819') // 'NWBK 601613 31926819'
formatterIban.toBBAN('GB29NWBK60161331926819', '-') // 'NWBK-601613-31926819'

formatterIban.isValidBBAN('GB', 'NWBK60161331926819') // true
formatterIban.fromBBAN('GB', 'NWBK60161331926819') // 'GB29NWBK60161331926819'
```

Locale-aware number formatting:

```ts
import { useFormatter } from '@bitrix24/b24jssdk'

const { formatterNumber } = useFormatter()

formatterNumber.format(1234) // '1,234' (integer, 'en' default)
formatterNumber.format(1234.567) // '1,234.57' (rounded to 2 decimals)
formatterNumber.format(1234.5, 'de') // '1.234,50'

formatterNumber.setDefLocale('ru')
formatterNumber.format(1234.5) // '1 234.50' (ru grouping, dot kept instead of comma)
```

## Alternatives and Recommendations

- **Use `formatterIban.isValid` to check user input before calling `printFormat`/`toBBAN`.** Both formatting methods only normalise the string — they do not validate the checksum, so an invalid IBAN can still be "printed" or converted.
- **Call `useFormatter()` once per module/component and destructure what you need.** Because both formatters are singletons, there is no benefit to caching the returned object yourself beyond avoiding the destructuring boilerplate.
- **For plain thousands/decimal formatting without locale awareness, prefer [`Text.numberFormat`](https://bitrix24.github.io/b24jssdk/raw/docs/working-with-the-rest-api/tools-text.md).** `formatterNumber.format` is locale-aware (via `Intl.NumberFormat`) and always rounds non-integers to exactly 2 decimals; `Text.numberFormat` lets you pick the number of decimals and the separators explicitly, which matches the server-side formatting used elsewhere in Bitrix24 REST payloads.
- **`addSpecification` exists mainly for internal use.** `useFormatter()` already registers every supported country on each call; `IbanSpecification` itself is not exported from `@bitrix24/b24jssdk`, so extending the country list from application code is not a supported public workflow today.

## Sitemap

See the full [sitemap](/b24jssdk/sitemap.md) for all pages.
