https://github.com/pitis/svelte-number-format
Svelte 5 lightweight and reactive number input component, built on top of intl-number-input
https://github.com/pitis/svelte-number-format
formatter formatting input svelte sveltekit typescript-library
Last synced: 4 months ago
JSON representation
Svelte 5 lightweight and reactive number input component, built on top of intl-number-input
- Host: GitHub
- URL: https://github.com/pitis/svelte-number-format
- Owner: pitis
- License: mit
- Created: 2022-01-08T19:59:13.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2025-12-28T02:34:57.000Z (7 months ago)
- Last Synced: 2026-03-26T19:11:50.994Z (4 months ago)
- Topics: formatter, formatting, input, svelte, sveltekit, typescript-library
- Language: Svelte
- Homepage: https://pitis.github.io/svelte-number-format/
- Size: 399 KB
- Stars: 33
- Watchers: 1
- Forks: 4
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# svelte-number-format
[](https://github.com/pitis/svelte-number-format/actions/workflows/ci.yml)
[](https://github.com/pitis/svelte-number-format/actions/workflows/deploy.yml)
[](https://www.npmjs.com/package/svelte-number-format)
**Svelte Number Format** is a lightweight and reactive input component library for [Svelte 5](https://svelte.dev).
Inspired by [react-number-format](https://www.npmjs.com/package/react-number-format), it provides two powerful components for handling formatted inputs with full caret stability and two-way binding.
## Features
✨ **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
## Live Demo
Check out the working demo: [https://pitis.github.io/svelte-number-format/](https://pitis.github.io/svelte-number-format/)
## Installation
```bash
npm install svelte-number-format
```
## Quick Start
### Currency Input
```svelte
import { NumericFormat, NumberFormatStyle } from 'svelte-number-format'
let amount = $state<number | null>(1234.56)
```
### Phone Number Input
```svelte
import { PatternFormat, MaskPatterns } from 'svelte-number-format'
let phone = $state<string | null>(null)
```
---
## NumericFormat Component
Locale-aware number formatting built on [intl-number-input](https://www.npmjs.com/package/intl-number-input).
### Props
| 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.) |
### Options
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`) |
### NumberFormatStyle Enum
```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%)
```
### Examples
#### Basic Number Input
```svelte
import { NumericFormat } from 'svelte-number-format'
let value = $state<number | null>(1234.56)
```
#### Currency (USD)
```svelte
import { NumericFormat, NumberFormatStyle } from 'svelte-number-format'
let price = $state<number | null>(99.99)
```
#### Currency (EUR with German locale)
```svelte
```
#### Percentage
```svelte
import { NumericFormat, NumberFormatStyle } from 'svelte-number-format'
let rate = $state<number | null>(0.75) // Store as decimal
```
#### With Value Range
```svelte
```
#### Auto Decimal Mode
```svelte
```
#### With Callbacks
```svelte
import { NumericFormat } from 'svelte-number-format'
let value = $state<number | null>(null)
function handleInput(raw: number | null, formatted: string | null) {
console.log('Input:', raw, formatted)
}
function handleChange(raw: number | null, formatted: string | null) {
console.log('Change:', raw, formatted)
}
```
---
## PatternFormat Component
Pattern-based input masking for structured text inputs.
### Props
| 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 |
### Pattern Characters
| Character | Accepts | Example |
| --------- | ------------------------ | ----------------------------- |
| `#` | Digit (0-9) | `###` → `123` |
| `A` | Letter (a-zA-Z) | `AAA` → `ABC` |
| `*` | Alphanumeric (a-zA-Z0-9) | `***` → `A1B` |
| Other | Literal | `-`, `(`, `)`, `/`, `:`, etc. |
### Predefined Patterns
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 // #******
```
### Examples
#### Phone Number
```svelte
import { PatternFormat, MaskPatterns } from 'svelte-number-format'
let phone = $state<string | null>(null)
```
#### Credit Card
```svelte
import { PatternFormat, MaskPatterns } from 'svelte-number-format'
let card = $state<string | null>(null)
```
#### Date
```svelte
```
#### Social Security Number
```svelte
```
#### Custom Pattern
```svelte
```
#### License Plate (Custom)
```svelte
```
#### Product Code (Custom)
```svelte
```
---
## Advanced Usage
### Controlled Components
Both components support controlled mode:
```svelte
import { NumericFormat } from 'svelte-number-format'
let amount = $state<number | null>(100)
(amount = 100)}>$100
(amount = 1000)}>$1,000
(amount = null)}>Clear
```
### Form Integration
```svelte
let formData = $state({
price: null as number | null,
phone: null as string | null
})
function handleSubmit() {
console.log('Form data:', formData)
}
Submit
```
### Custom Styling
```svelte
:global(.my-custom-input) {
padding: 1rem;
font-size: 1.5rem;
border-radius: 8px;
}
```
---
## Migration from v1.x
If you're upgrading from an earlier version, see [MIGRATION.md](./MIGRATION.md) for the full migration guide.
### Quick Migration
**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
- IE11+ with polyfills
---
## Contributing
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](./CONTRIBUTING.md) for detailed development setup and guidelines.
---
## License
MIT © [Pitis Radu](https://github.com/pitis)
---
## Acknowledgments
- Inspired by [react-number-format](https://www.npmjs.com/package/react-number-format)
- Built on [intl-number-input](https://www.npmjs.com/package/intl-number-input)