{"id":35132297,"url":"https://github.com/pitis/svelte-number-format","last_synced_at":"2026-04-07T06:31:31.131Z","repository":{"id":44934909,"uuid":"445915812","full_name":"pitis/svelte-number-format","owner":"pitis","description":"Svelte 5 lightweight and reactive number input component, built on top of intl-number-input","archived":false,"fork":false,"pushed_at":"2025-12-28T02:34:57.000Z","size":409,"stargazers_count":33,"open_issues_count":4,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-26T19:11:50.994Z","etag":null,"topics":["formatter","formatting","input","svelte","sveltekit","typescript-library"],"latest_commit_sha":null,"homepage":"https://pitis.github.io/svelte-number-format/","language":"Svelte","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pitis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-01-08T19:59:13.000Z","updated_at":"2026-02-06T10:09:56.000Z","dependencies_parsed_at":"2025-01-01T14:13:23.348Z","dependency_job_id":null,"html_url":"https://github.com/pitis/svelte-number-format","commit_stats":{"total_commits":11,"total_committers":1,"mean_commits":11.0,"dds":0.0,"last_synced_commit":"339c5a00a56b765d2dbf0e66a9c4f494959a56e5"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/pitis/svelte-number-format","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pitis%2Fsvelte-number-format","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pitis%2Fsvelte-number-format/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pitis%2Fsvelte-number-format/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pitis%2Fsvelte-number-format/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pitis","download_url":"https://codeload.github.com/pitis/svelte-number-format/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pitis%2Fsvelte-number-format/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31503381,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T03:10:19.677Z","status":"ssl_error","status_checked_at":"2026-04-07T03:10:13.982Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["formatter","formatting","input","svelte","sveltekit","typescript-library"],"created_at":"2025-12-28T06:34:55.271Z","updated_at":"2026-04-07T06:31:31.126Z","avatar_url":"https://github.com/pitis.png","language":"Svelte","funding_links":[],"categories":["Svelte"],"sub_categories":[],"readme":"# svelte-number-format\n\n[![CI](https://github.com/pitis/svelte-number-format/actions/workflows/ci.yml/badge.svg)](https://github.com/pitis/svelte-number-format/actions/workflows/ci.yml)\n[![Deploy](https://github.com/pitis/svelte-number-format/actions/workflows/deploy.yml/badge.svg)](https://github.com/pitis/svelte-number-format/actions/workflows/deploy.yml)\n[![npm version](https://badge.fury.io/js/svelte-number-format.svg)](https://www.npmjs.com/package/svelte-number-format)\n\n**Svelte Number Format** is a lightweight and reactive input component library for [Svelte 5](https://svelte.dev).  \nInspired 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.\n\n## Features\n\n✨ **Two Specialized Components**\n\n- **NumericFormat** - Locale-aware number formatting (currency, percentages, decimals)\n- **PatternFormat** - Pattern-based input masking (phone, credit cards, dates, custom)\n\n🎯 **Developer Experience**\n\n- Full TypeScript support\n- Two-way binding with `bind:value`\n- Svelte 5 native (using runes)\n- Caret position stability\n- Callback hooks for input/change events\n\n🌍 **Internationalization**\n\n- Built on `Intl.NumberFormat` API\n- Support for any locale\n- Automatic formatting based on locale\n\n## Live Demo\n\nCheck out the working demo: [https://pitis.github.io/svelte-number-format/](https://pitis.github.io/svelte-number-format/)\n\n## Installation\n\n```bash\nnpm install svelte-number-format\n```\n\n## Quick Start\n\n### Currency Input\n\n```svelte\n\u003cscript lang=\"ts\"\u003e\n  import { NumericFormat, NumberFormatStyle } from 'svelte-number-format'\n\n  let amount = $state\u003cnumber | null\u003e(1234.56)\n\u003c/script\u003e\n\n\u003cNumericFormat\n  bind:value={amount}\n  locale=\"en-US\"\n  options={{\n    formatStyle: NumberFormatStyle.Currency,\n    currency: 'USD',\n    precision: 2\n  }}\n  placeholder=\"$0.00\"\n/\u003e\n```\n\n### Phone Number Input\n\n```svelte\n\u003cscript lang=\"ts\"\u003e\n  import { PatternFormat, MaskPatterns } from 'svelte-number-format'\n\n  let phone = $state\u003cstring | null\u003e(null)\n\u003c/script\u003e\n\n\u003cPatternFormat\n  bind:value={phone}\n  format={MaskPatterns.PHONE_US}\n  placeholder=\"(123) 456-7890\"\n/\u003e\n```\n\n---\n\n## NumericFormat Component\n\nLocale-aware number formatting built on [intl-number-input](https://www.npmjs.com/package/intl-number-input).\n\n### Props\n\n| Prop       | Type                                                       | Default              | Description                                                          |\n| ---------- | ---------------------------------------------------------- | -------------------- | -------------------------------------------------------------------- |\n| `value`    | `number \\| null`                                           | `null`               | The numeric value. Use `bind:value` for two-way binding.             |\n| `locale`   | `string`                                                   | `navigator.language` | Locale string for formatting (e.g., `'en-US'`, `'de-DE'`, `'ja-JP'`) |\n| `options`  | `Partial\u003cNumberInputOptions\u003e`                              | `{}`                 | Formatting options (see below)                                       |\n| `onInput`  | `(raw: number \\| null, formatted: string \\| null) =\u003e void` | `undefined`          | Callback fired on every keystroke                                    |\n| `onChange` | `(raw: number \\| null, formatted: string \\| null) =\u003e void` | `undefined`          | Callback fired on blur/change                                        |\n| `...rest`  | `any`                                                      | -                    | All other HTML input attributes (`placeholder`, `class`, `id`, etc.) |\n\n### Options\n\nThe `options` prop accepts these properties:\n\n| Option              | Type                             | Description                                                                   |\n| ------------------- | -------------------------------- | ----------------------------------------------------------------------------- |\n| `formatStyle`       | `NumberFormatStyle`              | `Decimal`, `Currency`, or `Percent`                                           |\n| `currency`          | `string`                         | Currency code (e.g., `'USD'`, `'EUR'`, `'GBP'`) - required for Currency style |\n| `precision`         | `number`                         | Number of decimal places                                                      |\n| `valueRange`        | `{ min?: number, max?: number }` | Min/max value constraints                                                     |\n| `autoDecimalDigits` | `boolean`                        | Automatically position decimal (e.g., typing `1234` → `12.34`)                |\n\n### NumberFormatStyle Enum\n\n```typescript\nimport { NumberFormatStyle } from 'svelte-number-format'\n\nNumberFormatStyle.Decimal // Plain number with locale formatting\nNumberFormatStyle.Currency // Currency with symbol ($, €, £, etc.)\nNumberFormatStyle.Percent // Percentage (0.75 → 75%)\n```\n\n### Examples\n\n#### Basic Number Input\n\n```svelte\n\u003cscript lang=\"ts\"\u003e\n  import { NumericFormat } from 'svelte-number-format'\n  let value = $state\u003cnumber | null\u003e(1234.56)\n\u003c/script\u003e\n\n\u003cNumericFormat\n  bind:value\n  options={{ precision: 2 }}\n  placeholder=\"Enter amount\"\n/\u003e\n\u003c!-- User sees: 1,234.56 --\u003e\n```\n\n#### Currency (USD)\n\n```svelte\n\u003cscript lang=\"ts\"\u003e\n  import { NumericFormat, NumberFormatStyle } from 'svelte-number-format'\n  let price = $state\u003cnumber | null\u003e(99.99)\n\u003c/script\u003e\n\n\u003cNumericFormat\n  bind:value={price}\n  locale=\"en-US\"\n  options={{\n    formatStyle: NumberFormatStyle.Currency,\n    currency: 'USD',\n    precision: 2\n  }}\n/\u003e\n\u003c!-- User sees: $99.99 --\u003e\n```\n\n#### Currency (EUR with German locale)\n\n```svelte\n\u003cNumericFormat\n  bind:value={amount}\n  locale=\"de-DE\"\n  options={{\n    formatStyle: NumberFormatStyle.Currency,\n    currency: 'EUR',\n    precision: 2\n  }}\n/\u003e\n\u003c!-- User sees: 1.234,56 € --\u003e\n```\n\n#### Percentage\n\n```svelte\n\u003cscript lang=\"ts\"\u003e\n  import { NumericFormat, NumberFormatStyle } from 'svelte-number-format'\n  let rate = $state\u003cnumber | null\u003e(0.75) // Store as decimal\n\u003c/script\u003e\n\n\u003cNumericFormat\n  bind:value={rate}\n  options={{\n    formatStyle: NumberFormatStyle.Percent,\n    precision: 2\n  }}\n/\u003e\n\u003c!-- User sees: 75.00% --\u003e\n\u003c!-- Value stored as: 0.75 --\u003e\n```\n\n#### With Value Range\n\n```svelte\n\u003cNumericFormat\n  bind:value={amount}\n  options={{\n    precision: 2,\n    valueRange: { min: 0, max: 1000 }\n  }}\n  placeholder=\"0 - 1000\"\n/\u003e\n\u003c!-- Values are clamped to 0-1000 on blur --\u003e\n```\n\n#### Auto Decimal Mode\n\n```svelte\n\u003cNumericFormat\n  bind:value={price}\n  options={{\n    precision: 2,\n    autoDecimalDigits: true\n  }}\n  placeholder=\"Type 1234 → 12.34\"\n/\u003e\n\u003c!-- Typing \"1234\" automatically formats as \"12.34\" --\u003e\n```\n\n#### With Callbacks\n\n```svelte\n\u003cscript lang=\"ts\"\u003e\n  import { NumericFormat } from 'svelte-number-format'\n\n  let value = $state\u003cnumber | null\u003e(null)\n\n  function handleInput(raw: number | null, formatted: string | null) {\n    console.log('Input:', raw, formatted)\n  }\n\n  function handleChange(raw: number | null, formatted: string | null) {\n    console.log('Change:', raw, formatted)\n  }\n\u003c/script\u003e\n\n\u003cNumericFormat\n  bind:value\n  options={{ precision: 2 }}\n  onInput={handleInput}\n  onChange={handleChange}\n/\u003e\n```\n\n---\n\n## PatternFormat Component\n\nPattern-based input masking for structured text inputs.\n\n### Props\n\n| Prop          | Type                                                       | Default     | Description                                                              |\n| ------------- | ---------------------------------------------------------- | ----------- | ------------------------------------------------------------------------ |\n| `value`       | `string \\| null`                                           | `null`      | The raw unmasked value. Use `bind:value` for two-way binding.            |\n| `format`      | `string`                                                   | `''`        | Pattern string (e.g., `'(###) ###-####'`). See pattern characters below. |\n| `mask`        | `string`                                                   | `''`        | **Deprecated** - Use `format` instead. Kept for backwards compatibility. |\n| `maskChar`    | `string`                                                   | `'_'`       | Character shown in placeholder for pattern positions                     |\n| `placeholder` | `string`                                                   | auto        | Placeholder text (auto-generated from format if not provided)            |\n| `onInput`     | `(raw: string \\| null, formatted: string \\| null) =\u003e void` | `undefined` | Callback fired on every keystroke                                        |\n| `onChange`    | `(raw: string \\| null, formatted: string \\| null) =\u003e void` | `undefined` | Callback fired on blur/change                                            |\n| `...rest`     | `any`                                                      | -           | All other HTML input attributes                                          |\n\n### Pattern Characters\n\n| Character | Accepts                  | Example                       |\n| --------- | ------------------------ | ----------------------------- |\n| `#`       | Digit (0-9)              | `###` → `123`                 |\n| `A`       | Letter (a-zA-Z)          | `AAA` → `ABC`                 |\n| `*`       | Alphanumeric (a-zA-Z0-9) | `***` → `A1B`                 |\n| Other     | Literal                  | `-`, `(`, `)`, `/`, `:`, etc. |\n\n### Predefined Patterns\n\nImport ready-to-use patterns:\n\n```typescript\nimport { MaskPatterns } from 'svelte-number-format'\n```\n\n#### Phone Numbers\n\n```typescript\nMaskPatterns.PHONE_US // (###) ###-####\nMaskPatterns.PHONE_US_WITH_EXT // (###) ###-#### ext. #####\nMaskPatterns.PHONE_INTERNATIONAL // +## (###) ###-####\n```\n\n#### Credit Cards\n\n```typescript\nMaskPatterns.CREDIT_CARD // #### #### #### ####\nMaskPatterns.CREDIT_CARD_AMEX // #### ###### #####\n```\n\n#### Dates \u0026 Time\n\n```typescript\nMaskPatterns.DATE_US // ##/##/####\nMaskPatterns.DATE_ISO // ####-##-##\nMaskPatterns.DATE_EU // ##.##.####\nMaskPatterns.TIME_12H // ##:## AM\nMaskPatterns.TIME_24H // ##:##\nMaskPatterns.DATETIME_US // ##/##/#### ##:##\n```\n\n#### Identification\n\n```typescript\nMaskPatterns.SSN // ###-##-####\nMaskPatterns.ZIP_US // #####\nMaskPatterns.ZIP_US_PLUS4 // #####-####\n```\n\n#### Other\n\n```typescript\nMaskPatterns.IPV4 // ###.###.###.###\nMaskPatterns.MAC_ADDRESS // ##:##:##:##:##:##\nMaskPatterns.HEX_COLOR // #******\n```\n\n### Examples\n\n#### Phone Number\n\n```svelte\n\u003cscript lang=\"ts\"\u003e\n  import { PatternFormat, MaskPatterns } from 'svelte-number-format'\n  let phone = $state\u003cstring | null\u003e(null)\n\u003c/script\u003e\n\n\u003cPatternFormat bind:value={phone} format={MaskPatterns.PHONE_US} /\u003e\n\u003c!-- User types: 1234567890 --\u003e\n\u003c!-- Display: (123) 456-7890 --\u003e\n\u003c!-- Value stored: \"1234567890\" --\u003e\n```\n\n#### Credit Card\n\n```svelte\n\u003cscript lang=\"ts\"\u003e\n  import { PatternFormat, MaskPatterns } from 'svelte-number-format'\n  let card = $state\u003cstring | null\u003e(null)\n\u003c/script\u003e\n\n\u003cPatternFormat\n  bind:value={card}\n  format={MaskPatterns.CREDIT_CARD}\n  placeholder=\"1234 5678 9012 3456\"\n/\u003e\n\u003c!-- User types: 1234567890123456 --\u003e\n\u003c!-- Display: 1234 5678 9012 3456 --\u003e\n\u003c!-- Value stored: \"1234567890123456\" --\u003e\n```\n\n#### Date\n\n```svelte\n\u003cPatternFormat\n  bind:value={date}\n  format={MaskPatterns.DATE_US}\n  placeholder=\"MM/DD/YYYY\"\n/\u003e\n\u003c!-- User types: 12252024 --\u003e\n\u003c!-- Display: 12/25/2024 --\u003e\n\u003c!-- Value stored: \"12252024\" --\u003e\n```\n\n#### Social Security Number\n\n```svelte\n\u003cPatternFormat bind:value={ssn} format={MaskPatterns.SSN} /\u003e\n\u003c!-- Display: 123-45-6789 --\u003e\n\u003c!-- Value stored: \"123456789\" --\u003e\n```\n\n#### Custom Pattern\n\n```svelte\n\u003cPatternFormat\n  bind:value={code}\n  format=\"AAA-###-***\"\n  placeholder=\"ABC-123-XYZ\"\n/\u003e\n\u003c!-- Accepts: [Letter][Letter][Letter]-[Digit][Digit][Digit]-[Any][Any][Any] --\u003e\n\u003c!-- Example: ABC-123-X5Z --\u003e\n\u003c!-- Value stored: \"ABC123X5Z\" --\u003e\n```\n\n#### License Plate (Custom)\n\n```svelte\n\u003cPatternFormat bind:value={plate} format=\"AAA ####\" placeholder=\"ABC 1234\" /\u003e\n```\n\n#### Product Code (Custom)\n\n```svelte\n\u003cPatternFormat bind:value={product} format=\"***-***-***\" /\u003e\n\u003c!-- Accepts any combination of letters and numbers --\u003e\n```\n\n---\n\n## Advanced Usage\n\n### Controlled Components\n\nBoth components support controlled mode:\n\n```svelte\n\u003cscript lang=\"ts\"\u003e\n  import { NumericFormat } from 'svelte-number-format'\n  let amount = $state\u003cnumber | null\u003e(100)\n\u003c/script\u003e\n\n\u003cNumericFormat bind:value={amount} options={{ precision: 2 }} /\u003e\n\n\u003cbutton onclick={() =\u003e (amount = 100)}\u003e$100\u003c/button\u003e\n\u003cbutton onclick={() =\u003e (amount = 1000)}\u003e$1,000\u003c/button\u003e\n\u003cbutton onclick={() =\u003e (amount = null)}\u003eClear\u003c/button\u003e\n```\n\n### Form Integration\n\n```svelte\n\u003cscript lang=\"ts\"\u003e\n  let formData = $state({\n    price: null as number | null,\n    phone: null as string | null\n  })\n\n  function handleSubmit() {\n    console.log('Form data:', formData)\n  }\n\u003c/script\u003e\n\n\u003cform onsubmit={handleSubmit}\u003e\n  \u003cNumericFormat\n    bind:value={formData.price}\n    options={{ formatStyle: NumberFormatStyle.Currency, currency: 'USD' }}\n  /\u003e\n\n  \u003cPatternFormat bind:value={formData.phone} format={MaskPatterns.PHONE_US} /\u003e\n\n  \u003cbutton type=\"submit\"\u003eSubmit\u003c/button\u003e\n\u003c/form\u003e\n```\n\n### Custom Styling\n\n```svelte\n\u003cNumericFormat\n  bind:value={amount}\n  class=\"my-custom-input\"\n  style=\"border: 2px solid blue;\"\n/\u003e\n\n\u003cstyle\u003e\n  :global(.my-custom-input) {\n    padding: 1rem;\n    font-size: 1.5rem;\n    border-radius: 8px;\n  }\n\u003c/style\u003e\n```\n\n---\n\n## Migration from v1.x\n\nIf you're upgrading from an earlier version, see [MIGRATION.md](./MIGRATION.md) for the full migration guide.\n\n### Quick Migration\n\n**Old names** (still work):\n\n```svelte\nimport {(SvelteNumberFormat, SvelteMaskFormat)} from 'svelte-number-format';\n```\n\n**New names** (recommended):\n\n```svelte\nimport {(NumericFormat, PatternFormat)} from 'svelte-number-format';\n```\n\n---\n\n## TypeScript\n\nFull TypeScript support with proper type definitions:\n\n```typescript\nimport type { NumberInputOptions } from 'intl-number-input'\nimport {\n  NumericFormat,\n  PatternFormat,\n  NumberFormatStyle,\n  MaskPatterns\n} from 'svelte-number-format'\nimport type { MaskPattern } from 'svelte-number-format'\n```\n\n---\n\n## Browser Support\n\n- Svelte 5+\n- Modern browsers with `Intl.NumberFormat` support\n- IE11+ with polyfills\n\n---\n\n## Contributing\n\nContributions are welcome! This project uses:\n\n- **Husky** - Git hooks for quality checks\n- **lint-staged** - Run checks on staged files only\n- **Pre-commit hooks** - Automatic formatting, linting, and testing\n\nBefore each commit, the following runs automatically:\n\n- ✅ Prettier formatting\n- ✅ ESLint linting with auto-fix\n- ✅ Tests for changed files\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed development setup and guidelines.\n\n---\n\n## License\n\nMIT © [Pitis Radu](https://github.com/pitis)\n\n---\n\n## Acknowledgments\n\n- Inspired by [react-number-format](https://www.npmjs.com/package/react-number-format)\n- Built on [intl-number-input](https://www.npmjs.com/package/intl-number-input)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpitis%2Fsvelte-number-format","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpitis%2Fsvelte-number-format","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpitis%2Fsvelte-number-format/lists"}