FoodEase

Number Helpers

Utility functions for number formatting, validation, and manipulation

Overview

Number Helpers provide utility functions for working with numbers in various formats, including currency formatting, ordinal numbers, input validation, and numeric operations.

Installation

npx shadcn@latest add https://foodease-dev-registry.cap.reachcinema.io/r/v1/number-helpers.json

Functions

formatNumber

Format a number in a human-readable way with thousands separators, decimal places, and custom prefixes/suffixes.

import { formatNumber } from "@/lib/numberHelpers"

// Basic usage
formatNumber({ number: 123456 })
// Output: "123,456.00"

// Without decimals
formatNumber({ number: 123456, decimalAmount: 0 })
// Output: "123,456"

// Custom delimiter
formatNumber({ number: 123456, delimiter: " " })
// Output: "123 456.00"

// Currency
formatNumber({ number: 1234.56, prefix: "$" })
// Output: "$1,234.56"

// Negative numbers
formatNumber({ number: -1234.56, prefix: "$" })
// Output: "- $1,234.56"

Parameters:

interface Config {
  number: number | string          // The value to format
  decimalAmount?: number           // Number of decimal places (default: 2)
  decimalMark?: string             // Decimal indicator (default: ".")
  delimiter?: string               // Thousands separator (default: ",")
  prefix?: string                  // Text before number (e.g., "$")
  suffix?: string                  // Text after number (e.g., "%")
}

Examples:

// US currency
formatNumber({ number: 1234.56, prefix: "$", decimalAmount: 2 })
// "$1,234.56"

// European format
formatNumber({ 
  number: 1234.56, 
  prefix: "€", 
  delimiter: ".", 
  decimalMark: "," 
})
// "€1.234,56"

// Percentage
formatNumber({ number: 87.5, suffix: "%", decimalAmount: 1 })
// "87.5%"

// Large numbers
formatNumber({ number: 1000000, decimalAmount: 0 })
// "1,000,000"

formatOrdinal

Format a number using SI suffixes (K, M, G, T, P, E) for large numbers.

import { formatOrdinal } from "@/lib/numberHelpers"

formatOrdinal(1000)        // "1K"
formatOrdinal(1500)        // "2K" (rounded)
formatOrdinal(1500, 1)     // "1.5K" (1 decimal)
formatOrdinal(1000000)     // "1M"
formatOrdinal(1000000000)  // "1G"

Parameters:

  • num: number - The number to format
  • digits?: number - Number of decimal places (default: 0)

restrictToNumber

Restrict input to numeric digits only, preserving negative signs.

import { restrictToNumber } from "@/lib/numberHelpers"

restrictToNumber("abc123def")    // "123"
restrictToNumber("-123")         // "-123"
restrictToNumber("12.34.56")     // "123456"
restrictToNumber("$1,234")       // "1234"

// No leading zeros
restrictToNumber("0123", true)   // "123"

Parameters:

  • value?: string - The input string
  • noZero?: boolean - Remove leading zeros (default: false)

Use case: Perfect for PIN keyboards and integer-only inputs.

restrictToNumberAndOneDot

Restrict input to numeric digits and allow one decimal point.

import { restrictToNumberAndOneDot } from "@/lib/numberHelpers"

restrictToNumberAndOneDot("abc12.34def")   // "12.34"
restrictToNumberAndOneDot("12.34.56")      // "12.3456" (removes extra dots)
restrictToNumberAndOneDot("-123.45")       // "-123.45"
restrictToNumberAndOneDot("$1,234.56")     // "1234.56"

Parameters:

  • value?: string - The input string

Use case: Ideal for amount keyboards and decimal number inputs.

clamp

Constrain a number to be within a specified range.

import { clamp } from "@/lib/numberHelpers"

clamp(50, 0, 100)    // 50
clamp(150, 0, 100)   // 100 (clamped to max)
clamp(-10, 0, 100)   // 0 (clamped to min)

Parameters:

  • num: number - The number to clamp (default: 0)
  • min: number - Minimum value (default: 0)
  • max: number - Maximum value (default: 0)

formatRank

Format a number as an ordinal rank (1st, 2nd, 3rd, etc.).

import { formatRank } from "@/lib/numberHelpers"

formatRank(1)     // "1st"
formatRank(2)     // "2nd"
formatRank(3)     // "3rd"
formatRank(4)     // "4th"
formatRank(11)    // "11th"
formatRank(21)    // "21st"
formatRank(100)   // "100th"

Parameters:

  • number: number - The number to format

Examples

Currency Formatter Component

import { formatNumber } from "@/lib/numberHelpers"

export function Price({ amount }: { amount: number }) {
  return (
    <span>
      {formatNumber({ 
        number: amount, 
        prefix: "$", 
        decimalAmount: 2 
      })}
    </span>
  )
}

// Usage
<Price amount={1234.56} /> // "$1,234.56"

Validated Number Input

import { useState, ChangeEvent } from "react"
import { restrictToNumberAndOneDot } from "@/lib/numberHelpers"
import { Input } from "@/components/ui/input"

export function AmountInput() {
  const [value, setValue] = useState("")

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    const cleaned = restrictToNumberAndOneDot(e.target.value)
    setValue(cleaned)
  }

  return (
    <Input
      value={value}
      onChange={handleChange}
      placeholder="0.00"
    />
  )
}

File Size Formatter

import { formatOrdinal } from "@/lib/numberHelpers"

export function FileSize({ bytes }: { bytes: number }) {
  return <span>{formatOrdinal(bytes, 2)}B</span>
}

// Usage
<FileSize bytes={1024} />        // "1KB"
<FileSize bytes={1536} />        // "1.5KB"
<FileSize bytes={1048576} />     // "1MB"

Leaderboard Ranks

import { formatRank } from "@/lib/numberHelpers"

export function Leaderboard({ players }) {
  return (
    <ul>
      {players.map((player, index) => (
        <li key={player.id}>
          <span className="font-semibold">{formatRank(index + 1)}</span>
          {" "}{player.name} - {player.score}
        </li>
      ))}
    </ul>
  )
}

Range Slider with Clamp

import { useState } from "react"
import { clamp } from "@/lib/numberHelpers"

export function VolumeControl() {
  const [volume, setVolume] = useState(50)

  const adjustVolume = (delta: number) => {
    setVolume(prev => clamp(prev + delta, 0, 100))
  }

  return (
    <div>
      <button onClick={() => adjustVolume(-10)}>-</button>
      <span>{volume}%</span>
      <button onClick={() => adjustVolume(10)}>+</button>
    </div>
  )
}

Multi-Format Display

import { formatNumber, formatOrdinal, formatRank } from "@/lib/numberHelpers"

export function StatCard({ value, format }: { 
  value: number
  format: "currency" | "ordinal" | "rank" 
}) {
  const formatted = {
    currency: formatNumber({ number: value, prefix: "$", decimalAmount: 2 }),
    ordinal: formatOrdinal(value, 1),
    rank: formatRank(value),
  }[format]

  return <div className="stat-value">{formatted}</div>
}

Error Handling

formatNumber

Throws an error if:

  • Number is not valid (NaN)
  • Number exceeds Number.MAX_SAFE_INTEGER
try {
  formatNumber({ number: "invalid" })
} catch (error) {
  console.error(error) // "Number is not valid."
}

Type Definitions

interface Config {
  number: number | string
  decimalAmount?: number
  decimalMark?: string
  delimiter?: string
  prefix?: string
  suffix?: string
}

function formatNumber(config: Config): string
function formatOrdinal(num: number, digits?: number): string
function restrictToNumber(value?: string, noZero?: boolean): string
function restrictToNumberAndOneDot(value?: string): string
function clamp(num?: number, min?: number, max?: number): number
function formatRank(number: number): string

Dependencies

None - pure utility functions with no external dependencies.

On this page