Menu

Tailwind CSS Font Variant Numeric

Font Variant Numeric is a CSS property for styling numeric typograpy. It can profoundly influence the readability and style of a design, especially in contexts like financial documents, data tables, or any interface involving numerical data. It controls how numeric text is displayed, including options like proportional or tabular figures, slashed zeros, fractions, etc.

Tailwind CSS provides an extensive suite of utilities for managing font-variant-numeric styles. In this guide, we will dive deep into the utilities offered by Tailwind CSS for using Font Variant Numeric.

ClassPropertiesExample
normal-numsfont-variant-numeric: normal;<div className="normal-nums"></div>
ordinalfont-variant-numeric: ordinal;<div className="ordinal"></div>
slashed-zerofont-variant-numeric: slashed-zero;<div className="slashed-zero"></div>
lining-numsfont-variant-numeric: lining-nums;<div className="lining-nums"></div>
oldstyle-numsfont-variant-numeric: oldstyle-nums;<div className="oldstyle-nums"></div>
proportional-numsfont-variant-numeric: proportional-nums;<div className="proportional-nums"></div>
tabular-numsfont-variant-numeric: tabular-nums;<div className="tabular-nums"></div>
diagonal-fractionsfont-variant-numeric: diagonal-fractions;<div className="diagonal-fractions"></div>
stacked-fractionsfont-variant-numeric: stacked-fractions;<div className="stacked-fractions"></div>

Overview of Font Variant Numeric

Adding the Font Variant Numeric

To apply Font Variant Numeric styles, simply add the appropriate Tailwind utility class to your element, such as ordinal, slashed-zero, or lining-nums. Keep in mind that not all fonts support every numeric style, so ensure the font you’re using supports the specific style you want to apply.

Adding the Ordinal

Ordinal numbers (e.g., 1st, 2nd, 3rd) often get a typographic adjustment, elevating the letters like superscripts. Tailwind provides an ordinal utility to enable this feature.

This is a live editor. Play around with it!
export default function OrdinalExample() {
  return (
    <div className="font-sans text-xl w-screen h-screen bg-gray-200 flex items-center justify-center gap-1">
      <p className="ordinal">21st</p>
      <span>Century</span>
    </div>
  );
}

Adding the Slashed Zero

The slashed zero style adds a diagonal slash through zeros, improving clarity in contexts involving long sequences of numerical data where 0s and Os can be confused. Tailwind implements this through the slashed-zero utility.

This is a live editor. Play around with it!
export default function SlashedZeroDisplay() {
  return (
    <div className="font-[Inter] w-screen h-screen bg-gray-50 flex items-center justify-center">
      <p className="slashed-zero text-lg">Order ID: 10020</p>
    </div>
  );
}

Adding the Lining Figures

Lining figures are numeric styles where all digits have a consistent height and align neatly with uppercase letters. This is also the default style of most fonts. In Tailwind CSS, you can easily apply this style by using the lining-nums utility.

This is a live editor. Play around with it!
export default function LiningFiguresExample() {
  return (
    <div className="font-[Inter] w-screen h-screen bg-gray-300 flex items-center justify-center">
      <p className="lining-nums text-lg">1234567890</p>
    </div>
  );
}

Adding the Oldstyle Figures

Oldstyle Figures are a typographic style where numbers have varying heights and alignments. Unlike lining figures, oldstyle figures feature ascenders and descenders. In Tailwind CSS, the oldstyle-nums utility enables this style when supported by the font.

This is a live editor. Play around with it!
export default function OldStyleTypography() {
  return (
    <div className="font-[Georgia] w-screen h-screen bg-gray-100 flex items-center justify-center">
      <p className="oldstyle-nums text-lg">1234567890</p>
    </div>
  );
}

Adding the Proportional Figures

Proportional figures are numbers where each digit has a width that matches its design, creating a natural and visually pleasing flow when placed in running text. This style is ideal for content such as articles or paragraphs where numbers appear alongside letters, as the spacing feels more balanced. Tailwind’s proportional-nums utility enables proportional figures, provided the font supports this feature.

This is a live editor. Play around with it!
export default function ProportionalFiguresExample() {
  return (
    <div className="font-sans w-screen h-screen bg-gray-400 flex flex-col items-center justify-center text-lg">
      <p className="proportional-nums">
        111111
      </p>
      <p className="proportional-nums">
        897789
      </p>
    </div>
  );
}

Adding the Tabular Figures

Tabular figures are numbers with equal width, ensuring perfect alignment across rows and columns. This makes them ideal for tabular data, financial reports, or any layout where numerical values need to align vertically. In Tailwind CSS, the tabular-nums utility activates this style, making it easier to display structured and legible numeric content in supported fonts.

This is a live editor. Play around with it!
export default function TabularFiguresDisplay() {
  return (
    <div className="font-sans w-screen h-screen bg-gray-300 flex flex-col items-center justify-center">
      <p className="tabular-nums">
        111111
      </p>
      <p className="tabular-nums">
        897789
      </p>
    </div>
  );
}

Adding the Diagonal Fractions

Diagonal Fractions are a typographic style where fractions, such as ½ or ¾, are displayed with a diagonal slash separating the numerator and denominator. This style is compact, visually appealing, and commonly used in casual or inline text, such as recipes or technical specifications. Tailwind’s diagonal-fractions utility enables this style when supported by the font.

This is a live editor. Play around with it!
export default function FractionalTypography() {
  return (
    <div className="font-sans w-screen h-screen bg-gray-200 flex items-center justify-center">
      <p className="diagonal-fractions text-lg">1/2 cup sugar</p>
    </div>
  );
}

Resetting the Numeric Variants

When you need to reset numeric font variants after applying specific styles, use the normal-nums utility. This utility can be helpful when used with state or breakpoint modifiers.

This is a live editor. Play around with it!
export default function ResetNumericVariants() {
  return (
    <div className="font-[Inter] w-screen h-screen bg-gray-200 flex items-center justify-center">
      <p className="normal-nums text-lg">1111111</p>
    </div>
  );
}

States and Responsiveness

Tailwind allows numeric font styles to be applied conditionally using various state and responsive modifiers.

Hover and Focus States

You can dynamically apply font-variant-numeric styles by combining them with hover or focus states, e.g., hover:ordinal, focus:ordinal, etc.

This is a live editor. Play around with it!
export default function HoverFocusNumericStyle() {
  return (
    <div className="font-sans w-screen h-screen bg-gray-200 flex flex-col gap-6 items-center justify-center text-center px-10">
      <p className="underline">Hover on the below text to change the font variants</p>
      <p className="hover:ordinal text-lg">
        1st, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th
      </p>
    </div>
  );
}

Breakpoint Modifiers

You can also apply font-numeric-styles based on screen size with the help of breakpoint modifiers- sm, md, lg, etc.

This is a live editor. Play around with it!
export default function ResponsiveNumericStyling() {
  return (
    <div className="font-sans w-screen h-screen bg-gray-200 flex flex-col gap-6 items-center justify-center text-center px-10">
      <p className="underline">Ordinal utility will be active on "md" and above</p>
      <p className="md:ordinal text-lg">
        1st, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th
      </p>
    </div>
  );
}

Real World Examples

Financial Report Dashboard

A dashboard component displaying financial metrics with tabular numeric values using different font variant numeric styles.

This is a live editor. Play around with it!
export default function FinancialDashboard() {
  const financialData = [
    { metric: "Revenue", value: "$1,234,567.89", growth: "+12.5%", period: "2023" },
    { metric: "Operating Cost", value: "$876,543.21", growth: "-5.2%", period: "2023" },
    { metric: "Net Profit", value: "$358,024.68", growth: "+18.7%", period: "2023" },
    { metric: "Cash Flow", value: "$456,789.12", growth: "+8.9%", period: "2023" },
    { metric: "Assets", value: "$2,987,654.32", growth: "+15.3%", period: "2023" },
    { metric: "Liabilities", value: "$1,543,210.98", growth: "-3.4%", period: "2023" }
  ];

  return (
    <div className="p-6 bg-gray-50">
      <h2 className="text-2xl font-bold mb-6">Financial Overview</h2>
      <div className="grid grid-cols-1 gap-4">
        {financialData.map((item, index) => (
          <div key={index} className="bg-white p-4 rounded-lg shadow">
            <h3 className="text-gray-600">{item.metric}</h3>
            <p className="text-3xl font-sans font-bold tabular-nums">{item.value}</p>
            <span className={`text-sm ${item.growth.startsWith('+') ? 'text-green-500' : 'text-red-500'} proportional-nums`}>
              {item.growth}
            </span>
          </div>
        ))}
      </div>
    </div>
  );
}

Statistical Analysis Card

A component showing statistical data with different numeric styles for better readability.

This is a live editor. Play around with it!
export default function StatisticsCard() {
  const stats = [
    { title: "Sample Size", value: "1,234", decimal: "0.567", percentage: "89.4%" },
    { title: "Mean Value", value: "4,567", decimal: "0.890", percentage: "92.1%" },
    { title: "Median", value: "2,345", decimal: "0.123", percentage: "78.5%" },
    { title: "Standard Deviation", value: "3,456", decimal: "0.456", percentage: "95.7%" },
    { title: "Variance", value: "5,678", decimal: "0.789", percentage: "88.3%" },
    { title: "Confidence Level", value: "6,789", decimal: "0.234", percentage: "91.6%" }
  ];

  return (
    <div className="max-w-4xl mx-auto p-8">
      <div className="grid grid-cols-2 gap-6">
        {stats.map((stat, index) => (
          <div key={index} className="bg-indigo-50 p-6 rounded-xl">
            <h3 className="text-indigo-800 mb-4">{stat.title}</h3>
            <div className="space-y-2">
              <p className="text-2xl font-sans font-semibold tabular-nums">{stat.value}</p>
              <p className="text-lg font-sans proportional-nums">{stat.decimal}</p>
              <p className="font-[Georgia] text-xl oldstyle-nums">{stat.percentage}</p>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Sports Scoreboard

A live scoreboard component with different numeric styles for scores and statistics.

This is a live editor. Play around with it!
export default function SportsScoreboard() {
  const matches = [
    { team1: "Lakers", team2: "Warriors", score1: "108", score2: "115", quarter: "4th", time: "02:45" },
    { team1: "Celtics", team2: "Bulls", score1: "98", score2: "92", quarter: "3rd", time: "06:30" },
    { team1: "Nets", team2: "Heat", score1: "87", score2: "89", quarter: "2nd", time: "04:15" },
    { team1: "Suns", team2: "Clippers", score1: "76", score2: "72", quarter: "1st", time: "08:20" },
    { team1: "Bucks", team2: "76ers", score1: "95", score2: "99", quarter: "4th", time: "01:55" },
    { team1: "Mavericks", team2: "Spurs", score1: "112", score2: "105", quarter: "Final", time: "00:00" }
  ];

  return (
    <div className="bg-gray-900 p-6 text-white">
      <h2 className="text-2xl mb-6">Live Scores</h2>
      <div className="space-y-4">
        {matches.map((match, index) => (
          <div key={index} className="font-sans bg-gray-800 p-4 rounded-lg flex justify-between items-center">
            <div className="flex flex-col flex-1 text-center">
              <span className="text-2xl mx-4 tabular-nums">{match.score1}</span>
              <span className="text-xl">{match.team1}</span>
            </div>
            <div className="text-center px-8">
              <span className="text-sm ordinal">{match.quarter}</span>
              <br />
              <span className="text-lg proportional-nums">{match.time}</span>
            </div>
            <div className="flex flex-col flex-1 text-center">
              <span className="text-2xl mx-4 tabular-nums">{match.score2}</span>
              <span className="text-xl">{match.team2}</span>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

Stock Market Ticker

A stock market ticker component with different numeric styles for prices and changes.

This is a live editor. Play around with it!
export default function StockTicker() {
  const stocks = [
    { symbol: "AAPL", price: "156.78", change: "+2.45", volume: "12.5M" },
    { symbol: "GOOGL", price: "2,789.45", change: "-15.67", volume: "8.2M" },
    { symbol: "MSFT", price: "345.23", change: "+5.89", volume: "10.1M" },
    { symbol: "AMZN", price: "3,456.78", change: "-28.90", volume: "15.7M" },
    { symbol: "TSLA", price: "789.12", change: "+12.34", volume: "20.3M" },
    { symbol: "META", price: "234.56", change: "+1.23", volume: "9.8M" }
  ];

  return (
    <div className="bg-black p-6">
      <div className="flex flex-wrap gap-4">
        {stocks.map((stock, index) => (
          <div key={index} className="font-sans bg-gray-900 p-4 rounded-lg text-white">
            <h3 className="text-lg font-bold">{stock.symbol}</h3>
            <p className="text-2xl tabular-nums">${stock.price}</p>
            <p className={`text-sm ${stock.change.startsWith('+') ? 'text-green-400' : 'text-red-400'} proportional-nums`}>
              {stock.change}
            </p>
            <p className="text-gray-400">Vol: {stock.volume}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

Scientific Calculator Display

A calculator display component with different numeric styles for different types of numbers.

This is a live editor. Play around with it!
export default function CalculatorDisplay() {
  const calculations = [
    { expression: "√256", result: "16.0000", type: "root" },
    { expression: "sin(45°)", result: "0.7071", type: "trigonometry" },
    { expression: "log(100)", result: "2.0000", type: "logarithm" },
    { expression: "e^2", result: "7.3891", type: "exponential" },
    { expression: "3.14159", result: "Ï€", type: "constant" },
    { expression: "75!", result: "2.4809×10^109", type: "factorial" }
  ];

  return (
    <div className="bg-gray-100 p-6">
      <div className="font-[Inter] max-w-md mx-auto bg-white rounded-xl shadow-lg p-6">
        <div className="space-y-4">
          {calculations.map((calc, index) => (
            <div key={index} className="border-b border-gray-200 pb-3">
              <div className="flex justify-between items-center">
                <span className="text-gray-600 proportional-nums">{calc.expression}</span>
                <span className="text-xl slashed-zero tabular-nums">{calc.result}</span>
              </div>
              <span className="text-sm text-gray-500">{calc.type}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

Best Practices

Maintain Design Consistency

When using font variant numeric utilities, align the numeric style with the overall design system. For example, if tabular-nums is chosen for a data-heavy dashboard, all numerical elements should follow the same rule to maintain a uniform grid. Avoid mixing lining-nums and oldstyle-nums randomly within the same context, as it can create a disjointed reading experience.

For structured content like invoices or time logs, standardizing numeric typography ensures that all numbers align correctly. Establish guidelines on when and where each style should be applied, ensuring that designers and developers maintain coherence across the UI.

Leverage Utility Combinations

Combining font variant numeric utilities with other utilities like- font size, font family, letter spacing, etc. help to enhance clarity and usability. Thoughtfully integrating spacing, color, and typography can enhance legibility and create a visually appealing interface.

When presenting numbers in an interactive setting, such as a calculator or stock tracker, consider using tabular-nums alongside text-right to align numerical content neatly. This pairing avoids jagged edges and improves scanability. Additionally, using slashed-zero with monospaced fonts enhances differentiation between similar characters (e.g., 0 and O), reducing ambiguity.

Accessibility Considerations

Enhance Readability and Navigability

The choice between tabular-nums and proportional-nums can significantly impact how numbers appear in structured layouts, particularly for users with cognitive impairments or reading difficulties.

Using tabular-nums for data tables improves clarity by maintaining a consistent width, allowing readers to interpret numbers without unexpected spacing inconsistencies. This prevents issues where misaligned numbers become difficult to track. For general text, proportional-nums ensures that numbers blend naturally within paragraphs, enhancing readability without creating unnecessary visual disruptions.

Focus on High Contrast

Ensuring sufficient contrast for numeric text is crucial for accessibility, particularly for users with low vision. When using font variant numeric utilities, it's important to pair them with high-contrast colors. Without adequate contrast, numbers can become difficult to distinguish.

Consider using dark text on a light background or light text on a dark background. Additionally, applying high font weight or letter spacing to further enhance legibility.

Beyond basic contrast considerations, it’s essential to meet the Web Content Accessibility Guidelines (WCAG) contrast ratio recommendations. For normal text, the minimum required contrast ratio is 4.5:1, while larger text should maintain at least 3:1 contrast.