Lightweight and reactive input formatting library for Svelte 5. Includes NumericFormat for numbers/currency and PatternFormat for phone, cards, dates, and custom masks.
npm install svelte-number-format


Svelte Number Format is a lightweight and reactive input component library for Svelte 5.
Inspired by react-number-format, it provides two powerful components for handling formatted inputs with full caret stability and two-way binding.
β¨ Two Specialized Components
- NumericFormat - Locale-aware number formatting (currency, percentages, decimals)
- PatternFormat - Pattern-based input masking (phone, credit cards, dates, custom)
π― Developer Experience
- Full TypeScript support
- Two-way binding with bind:value
- Svelte 5 native (using runes)
- Caret position stability
- Callback hooks for input/change events
π Internationalization
- Built on Intl.NumberFormat API
- Support for any locale
- Automatic formatting based on locale
Check out the working demo: https://pitis.github.io/svelte-number-format/
``bash`
npm install svelte-number-format
`svelte
locale="en-US"
options={{
formatStyle: NumberFormatStyle.Currency,
currency: 'USD',
precision: 2
}}
placeholder="$0.00"
/>
`
`svelte
format={MaskPatterns.PHONE_US}
placeholder="(123) 456-7890"
/>
`
---
Locale-aware number formatting built on intl-number-input.
| Prop | Type | Default | Description |
| ---------- | ---------------------------------------------------------- | -------------------- | -------------------------------------------------------------------- |
| value | number \| null | null | The numeric value. Use bind:value for two-way binding. |locale
| | string | navigator.language | Locale string for formatting (e.g., 'en-US', 'de-DE', 'ja-JP') |options
| | Partial | {} | Formatting options (see below) |onInput
| | (raw: number \| null, formatted: string \| null) => void | undefined | Callback fired on every keystroke |onChange
| | (raw: number \| null, formatted: string \| null) => void | undefined | Callback fired on blur/change |...rest
| | any | - | All other HTML input attributes (placeholder, class, id, etc.) |
The options prop accepts these properties:
| Option | Type | Description |
| ------------------- | -------------------------------- | ----------------------------------------------------------------------------- |
| formatStyle | NumberFormatStyle | Decimal, Currency, or Percent |currency
| | string | Currency code (e.g., 'USD', 'EUR', 'GBP') - required for Currency style |precision
| | number | Number of decimal places |valueRange
| | { min?: number, max?: number } | Min/max value constraints |autoDecimalDigits
| | boolean | Automatically position decimal (e.g., typing 1234 β 12.34) |
`typescript
import { NumberFormatStyle } from 'svelte-number-format'
NumberFormatStyle.Decimal // Plain number with locale formatting
NumberFormatStyle.Currency // Currency with symbol ($, β¬, Β£, etc.)
NumberFormatStyle.Percent // Percentage (0.75 β 75%)
`
#### Basic Number Input
`svelte
options={{ precision: 2 }}
placeholder="Enter amount"
/>
`
#### Currency (USD)
`svelte
locale="en-US"
options={{
formatStyle: NumberFormatStyle.Currency,
currency: 'USD',
precision: 2
}}
/>
`
#### Currency (EUR with German locale)
`svelte`
locale="de-DE"
options={{
formatStyle: NumberFormatStyle.Currency,
currency: 'EUR',
precision: 2
}}
/>
#### Percentage
`svelte
options={{
formatStyle: NumberFormatStyle.Percent,
precision: 2
}}
/>
`
#### With Value Range
`svelte`
options={{
precision: 2,
valueRange: { min: 0, max: 1000 }
}}
placeholder="0 - 1000"
/>
#### Auto Decimal Mode
`svelte`
options={{
precision: 2,
autoDecimalDigits: true
}}
placeholder="Type 1234 β 12.34"
/>
#### With Callbacks
`svelte
options={{ precision: 2 }}
onInput={handleInput}
onChange={handleChange}
/>
`
---
Pattern-based input masking for structured text inputs.
| Prop | Type | Default | Description |
| ------------- | ---------------------------------------------------------- | ----------- | ------------------------------------------------------------------------ |
| value | string \| null | null | The raw unmasked value. Use bind:value for two-way binding. |format
| | string | '' | Pattern string (e.g., '(###) ###-####'). See pattern characters below. |mask
| | string | '' | Deprecated - Use format instead. Kept for backwards compatibility. |maskChar
| | string | '_' | Character shown in placeholder for pattern positions |placeholder
| | string | auto | Placeholder text (auto-generated from format if not provided) |onInput
| | (raw: string \| null, formatted: string \| null) => void | undefined | Callback fired on every keystroke |onChange
| | (raw: string \| null, formatted: string \| null) => void | undefined | Callback fired on blur/change |...rest
| | any | - | All other HTML input attributes |
| Character | Accepts | Example |
| --------- | ------------------------ | ----------------------------- |
| # | Digit (0-9) | ### β 123 |A
| | Letter (a-zA-Z) | AAA β ABC |
| | Alphanumeric (a-zA-Z0-9) | ** β A1B |-
| Other | Literal | , (, ), /, :, etc. |
Import ready-to-use patterns:
`typescript`
import { MaskPatterns } from 'svelte-number-format'
#### Phone Numbers
`typescript`
MaskPatterns.PHONE_US // (###) ###-####
MaskPatterns.PHONE_US_WITH_EXT // (###) ###-#### ext. #####
MaskPatterns.PHONE_INTERNATIONAL // +## (###) ###-####
#### Credit Cards
`typescript`
MaskPatterns.CREDIT_CARD // #### #### #### ####
MaskPatterns.CREDIT_CARD_AMEX // #### ###### #####
#### Dates & Time
`typescript`
MaskPatterns.DATE_US // ##/##/####
MaskPatterns.DATE_ISO // ####-##-##
MaskPatterns.DATE_EU // ##.##.####
MaskPatterns.TIME_12H // ##:## AM
MaskPatterns.TIME_24H // ##:##
MaskPatterns.DATETIME_US // ##/##/#### ##:##
#### Identification
`typescript`
MaskPatterns.SSN // ###-##-####
MaskPatterns.ZIP_US // #####
MaskPatterns.ZIP_US_PLUS4 // #####-####
#### Other
`typescript`
MaskPatterns.IPV4 // ###.###.###.###
MaskPatterns.MAC_ADDRESS // ##:##:##:##:##:##
MaskPatterns.HEX_COLOR // #
#### Phone Number
`svelte
`
#### Credit Card
`svelte
format={MaskPatterns.CREDIT_CARD}
placeholder="1234 5678 9012 3456"
/>
`
#### Date
`svelte`
format={MaskPatterns.DATE_US}
placeholder="MM/DD/YYYY"
/>
#### Social Security Number
`svelte`
#### Custom Pattern
`svelte`
format="AAA-###-*"
placeholder="ABC-123-XYZ"
/>
#### License Plate (Custom)
`svelte`
#### Product Code (Custom)
`svelte`
---
Both components support controlled mode:
`svelte
`
`svelte
$3
`svelte
bind:value={amount}
class="my-custom-input"
style="border: 2px solid blue;"
/>
`---
Migration from v1.x
If you're upgrading from an earlier version, see MIGRATION.md for the full migration guide.
$3
Old names (still work):
`svelte
import {(SvelteNumberFormat, SvelteMaskFormat)} from 'svelte-number-format';
`New names (recommended):
`svelte
import {(NumericFormat, PatternFormat)} from 'svelte-number-format';
`---
TypeScript
Full TypeScript support with proper type definitions:
`typescript
import type { NumberInputOptions } from 'intl-number-input'
import {
NumericFormat,
PatternFormat,
NumberFormatStyle,
MaskPatterns
} from 'svelte-number-format'
import type { MaskPattern } from 'svelte-number-format'
`---
Browser Support
- Svelte 5+
- Modern browsers with
Intl.NumberFormat` support---
Contributions are welcome! This project uses:
- Husky - Git hooks for quality checks
- lint-staged - Run checks on staged files only
- Pre-commit hooks - Automatic formatting, linting, and testing
Before each commit, the following runs automatically:
- β
Prettier formatting
- β
ESLint linting with auto-fix
- β
Tests for changed files
See CONTRIBUTING.md for detailed development setup and guidelines.
---
MIT Β© Pitis Radu
---
- Inspired by react-number-format
- Built on intl-number-input