DEV Community

Cover image for Display Rupiah Values Beautifully with formatCompact()
Adamm
Adamm

Posted on

Display Rupiah Values Beautifully with formatCompact()

Display Rupiah Values Beautifully with formatCompact()

Ever noticed how Instagram shows "1.2M likes" instead of "1,200,000 likes"? That's compact formatting - and your Indonesian apps need it too.

Large numbers like Rp 1.500.000.000 take up too much space and are hard to read at a glance. That's why I built formatCompact() in @indodev/toolkit - it formats Rupiah using Indonesian units: ribu, juta, miliar, triliun.

Installation

npm install @indodev/toolkit
Enter fullscreen mode Exit fullscreen mode

Basic Usage

import { formatCompact } from '@indodev/toolkit';

formatCompact(1500000);
// → 'Rp 1,5 juta'

formatCompact(1000000);
// → 'Rp 1 juta'  // Note: proper Indonesian grammar!
Enter fullscreen mode Exit fullscreen mode

Notice how it outputs "1 juta" not "1,0 juta"? That's proper Indonesian grammar built-in.

Real-World Use Cases

1. Dashboard Statistics

Perfect for KPI cards and metrics:

const stats = {
  revenue: 125000000,
  users: 450000,
  transactions: 1500000000
};

console.log(`Revenue: ${formatCompact(stats.revenue)}`);
console.log(`Active Users: ${formatCompact(stats.users)}`);
console.log(`GMV: ${formatCompact(stats.transactions)}`);

// Output:
// Revenue: Rp 125 juta
// Active Users: Rp 450 ribu
// GMV: Rp 1,5 miliar
Enter fullscreen mode Exit fullscreen mode

Much cleaner than "Rp 125.000.000", right?

2. Social Media Posts

Show funding announcements or milestones:

const announcements = [
  { company: 'Tokopedia', funding: 1500000000000 },
  { company: 'Gojek', funding: 3000000000000 },
  { company: 'Bukalapak', funding: 850000000000 }
];

announcements.forEach(a => {
  console.log(`${a.company} raised ${formatCompact(a.funding)}! 🚀`);
});

// Output:
// Tokopedia raised Rp 1,5 triliun! 🚀
// Gojek raised Rp 3 triliun! 🚀
// Bukalapak raised Rp 850 miliar! 🚀
Enter fullscreen mode Exit fullscreen mode

3. E-commerce Product Listings

When space is limited (mobile cards, grids):

const products = [
  { name: 'iPhone 15 Pro', price: 18000000 },
  { name: 'MacBook Air M2', price: 16500000 },
  { name: 'AirPods Pro', price: 3500000 }
];

// Mobile card view
products.forEach(p => {
  console.log(`${p.name}\n${formatCompact(p.price)}\n`);
});

// Output:
// iPhone 15 Pro
// Rp 18 juta
//
// MacBook Air M2
// Rp 16,5 juta
//
// AirPods Pro
// Rp 3,5 juta
Enter fullscreen mode Exit fullscreen mode

4. Real Estate Listings

Property prices with clean display:

const properties = [
  { type: 'Apartment', price: 850000000 },
  { type: 'House', price: 2500000000 },
  { type: 'Villa', price: 5200000000 }
];

properties.forEach(p => {
  console.log(`${p.type}: ${formatCompact(p.price)}`);
});

// Output:
// Apartment: Rp 850 juta
// House: Rp 2,5 miliar
// Villa: Rp 5,2 miliar
Enter fullscreen mode Exit fullscreen mode

5. Chart Labels

Keep your charts readable:

const monthlyRevenue = [
  { month: 'Jan', revenue: 450000000 },
  { month: 'Feb', revenue: 520000000 },
  { month: 'Mar', revenue: 680000000 },
  { month: 'Apr', revenue: 1200000000 }
];

// For chart Y-axis labels
const chartData = monthlyRevenue.map(data => ({
  x: data.month,
  y: data.revenue,
  label: formatCompact(data.revenue)
}));

console.log(chartData);

// Output:
// [
//   { x: 'Jan', y: 450000000, label: 'Rp 450 juta' },
//   { x: 'Feb', y: 520000000, label: 'Rp 520 juta' },
//   { x: 'Mar', y: 680000000, label: 'Rp 680 juta' },
//   { x: 'Apr', y: 1200000000, label: 'Rp 1,2 miliar' }
// ]
Enter fullscreen mode Exit fullscreen mode

6. Financial News App

Display market cap, volume, etc:

const stockInfo = {
  company: 'Bank BCA',
  marketCap: 985000000000000,
  volume: 125000000000
};

console.log(`${stockInfo.company}`);
console.log(`Market Cap: ${formatCompact(stockInfo.marketCap)}`);
console.log(`Volume: ${formatCompact(stockInfo.volume)}`);

// Output:
// Bank BCA
// Market Cap: Rp 985 triliun
// Volume: Rp 125 miliar
Enter fullscreen mode Exit fullscreen mode

7. Startup Pitch Decks

Show traction metrics cleanly:

const metrics = {
  arr: 12000000000,        // Annual Recurring Revenue
  mrr: 1000000000,         // Monthly Recurring Revenue
  runway: 24000000000      // Cash runway
};

console.log('📊 Key Metrics');
console.log(`ARR: ${formatCompact(metrics.arr)}`);
console.log(`MRR: ${formatCompact(metrics.mrr)}`);
console.log(`Runway: ${formatCompact(metrics.runway)}`);

// Output:
// 📊 Key Metrics
// ARR: Rp 12 miliar
// MRR: Rp 1 miliar
// Runway: Rp 24 miliar
Enter fullscreen mode Exit fullscreen mode

8. Handling Edge Cases

The function smartly handles different ranges:

// Trillions
formatCompact(1500000000000);  // → 'Rp 1,5 triliun'

// Billions
formatCompact(2500000000);     // → 'Rp 2,5 miliar'

// Millions
formatCompact(3500000);        // → 'Rp 3,5 juta'

// Hundreds of thousands (uses 'ribu')
formatCompact(500000);         // → 'Rp 500 ribu'

// Below 100k (standard format, not compact)
formatCompact(85000);          // → 'Rp 85.000'
formatCompact(1500);           // → 'Rp 1.500'

// Negative values
formatCompact(-1500000);       // → '-Rp 1,5 juta'
Enter fullscreen mode Exit fullscreen mode

When to Use formatCompact vs formatRupiah

Use formatCompact() when:

  • Space is limited (mobile cards, tooltips)
  • Quick scanning is important (dashboards, charts)
  • Exact values don't matter (social media, announcements)

Use formatRupiah() when:

  • Exact amounts matter (invoices, receipts)
  • Official documents (contracts, reports)
  • Payment screens (checkout, transfers)

Example: Hybrid Approach

import { formatCompact, formatRupiah } from '@indodev/toolkit';

// Product card (compact)
const cardPrice = formatCompact(15000000);  // 'Rp 15 juta'

// Checkout page (exact)
const checkoutPrice = formatRupiah(15000000);  // 'Rp 15.000.000'

// Tooltip (both!)
const tooltip = `${cardPrice} (${formatRupiah(15000000, { symbol: false })})`;
// 'Rp 15 juta (15.000.000)'
Enter fullscreen mode Exit fullscreen mode

Indonesian Grammar Rules Built-In

The function follows proper Indonesian grammar:

  • ✅ "1 juta" not "1,0 juta"
  • ✅ "1,5 juta" for 1.5 million
  • ✅ Uses comma (,) for decimals
  • ✅ Automatically rounds to 1 decimal place

TypeScript Support

import { formatCompact } from '@indodev/toolkit';

// Fully typed
const formatted: string = formatCompact(1500000);

// Works with computed values
const total = prices.reduce((sum, p) => sum + p, 0);
const display = formatCompact(total);
Enter fullscreen mode Exit fullscreen mode

Why Use This?

  • Zero dependencies - just 30KB total
  • Proper Indonesian - follows local grammar rules
  • Smart rounding - removes unnecessary decimals
  • Wide range support - from thousands to trillions
  • Battle-tested - 95%+ test coverage

What's Next?

Explore other utilities in @indodev/toolkit:

  • formatRupiah() - Full Rupiah formatting with options
  • validateNIK() - Validate Indonesian National ID
  • validatePhoneNumber() - Phone number validation

Get started:

npm install @indodev/toolkit
Enter fullscreen mode Exit fullscreen mode

Make your UI cleaner today! 🚀

Top comments (0)