Vercel wordmark
Tremor is joining Vercel.

Getting Started

Next.js

Everything you need to set up Tremor with Next.js.

Installation

Tremor is designed for React and requires React v18.2.0+

  1. 1

    Create a new Next.js project:

    In our terminal, we create a new Next.js project. Stick to Tailwind CSS, use the src/ directory and the app router.
    npx create-next-app@14.2.28 my-project --ts --tailwind --eslint --app --src-dir && cd my-project
    Next 14 will come with Tailwind v3 preinstalled, so we have to update to version 4, run:
    npx @tailwindcss/upgrade
  2. 2

    Install dependencies:

    To install the core dependencies, run:

    npm install tailwind-variants clsx tailwind-merge @remixicon/react

    (Optional) If you plan to use all components, you can add all dependencies here:

    npm install @radix-ui/react-accordion @radix-ui/react-checkbox @radix-ui/react-dialog @radix-ui/react-dropdown-menu @radix-ui/react-hover-card @radix-ui/react-label @radix-ui/react-navigation-menu @radix-ui/react-popover @radix-ui/react-radio-group @radix-ui/react-select @radix-ui/react-slider @radix-ui/react-slot @radix-ui/react-switch @radix-ui/react-tabs @radix-ui/react-toast @radix-ui/react-tooltip @radix-ui/react-toggle-group @radix-ui/react-toggle @internationalized/date date-fns@3.6.0 react-day-picker@8.10.1 recharts @react-aria/datepicker @react-stately/datepicker
  3. 3

    Add font and dark mode background:

    In all our examples, we use Geist Font. This is not required, use any other font you like. To install, run:

    npm install geist

    Then in your app/layout.tsx, add the font and dark mode background like this:

    import type { Metadata } from "next";import { GeistSans } from "geist/font/sans"; // import fontimport "./globals.css";
    export const metadata: Metadata = {  title: "Create Next App",  description: "Generated by create next app",};
    export default function RootLayout({  children,}: Readonly<{  children: React.ReactNode;}>) {  return (    // add font to className, also add antialiased and dark mode    <html lang="en" className={`${GeistSans.className} antialiased dark:bg-gray-950`}>      <body>{children}</body>    </html>  );}
  4. 4

    Install @tailwindcss/forms

    To install, run:

    npm install -D @tailwindcss/forms
  5. 5

    Update globals.css

    In order for the animations to be applied correctly, we extend the globals.css. We also import the @tailwindcss/forms plugin.

    @import "tailwindcss";@plugin "@tailwindcss/forms";
    @custom-variant dark (&:where(.dark, .dark *));
    @theme {  --animate-hide: hide 150ms cubic-bezier(0.16, 1, 0.3, 1);  --animate-slide-down-and-fade: slideDownAndFade 150ms    cubic-bezier(0.16, 1, 0.3, 1);  --animate-slide-left-and-fade: slideLeftAndFade 150ms    cubic-bezier(0.16, 1, 0.3, 1);  --animate-slide-up-and-fade: slideUpAndFade 150ms    cubic-bezier(0.16, 1, 0.3, 1);  --animate-slide-right-and-fade: slideRightAndFade 150ms    cubic-bezier(0.16, 1, 0.3, 1);  --animate-accordion-open: accordionOpen 150ms cubic-bezier(0.87, 0, 0.13, 1);  --animate-accordion-close: accordionClose 150ms cubic-bezier(0.87, 0, 0.13, 1);  --animate-dialog-overlay-show: dialogOverlayShow 150ms    cubic-bezier(0.16, 1, 0.3, 1);  --animate-dialog-content-show: dialogContentShow 150ms    cubic-bezier(0.16, 1, 0.3, 1);  --animate-drawer-slide-left-and-fade: drawerSlideLeftAndFade 150ms    cubic-bezier(0.16, 1, 0.3, 1);  --animate-drawer-slide-right-and-fade: drawerSlideRightAndFade 150ms ease-in;
      @keyframes hide {    from {      opacity: 1;    }    to {      opacity: 0;    }  }  @keyframes slideDownAndFade {    from {      opacity: 0;      transform: translateY(-6px);    }    to {      opacity: 1;      transform: translateY(0);    }  }  @keyframes slideLeftAndFade {    from {      opacity: 0;      transform: translateX(6px);    }    to {      opacity: 1;      transform: translateX(0);    }  }  @keyframes slideUpAndFade {    from {      opacity: 0;      transform: translateY(6px);    }    to {      opacity: 1;      transform: translateY(0);    }  }  @keyframes slideRightAndFade {    from {      opacity: 0;      transform: translateX(-6px);    }    to {      opacity: 1;      transform: translateX(0);    }  }  @keyframes accordionOpen {    from {      height: 0px;    }    to {      height: var(--radix-accordion-content-height);    }  }  @keyframes accordionClose {    from {      height: var(--radix-accordion-content-height);    }    to {      height: 0px;    }  }  @keyframes dialogOverlayShow {    from {      opacity: 0;    }    to {      opacity: 1;    }  }  @keyframes dialogContentShow {    from {      opacity: 0;      transform: translate(-50%, -45%) scale(0.95);    }    to {      opacity: 1;      transform: translate(-50%, -50%) scale(1);    }  }  @keyframes drawerSlideLeftAndFade {    from {      opacity: 0;      transform: translateX(100%);    }    to {      opacity: 1;      transform: translateX(0);    }  }  @keyframes drawerSlideRightAndFade {    from {      opacity: 1;      transform: translateX(0);    }    to {      opacity: 0;      transform: translateX(100%);    }  }}
  6. 6

    Add utilities and helpers

    Our components depend on a few utilities. You can read more about them in the Utilities section.

    Create a new lib folder in /src. Add a new utils.ts file inside. Paste the following utilities into this file.

    // Tremor Raw cx [v0.0.0]
    import clsx, { type ClassValue } from "clsx"import { twMerge } from "tailwind-merge"
    export function cx(...args: ClassValue[]) {  return twMerge(clsx(...args))}
    // Tremor focusInput [v0.0.2]
    export const focusInput = [  // base  "focus:ring-2",  // ring color  "focus:ring-blue-200 dark:focus:ring-blue-700/30",  // border color  "focus:border-blue-500 dark:focus:border-blue-700",]
    // Tremor Raw focusRing [v0.0.1]
    export const focusRing = [  // base  "outline outline-offset-2 outline-0 focus-visible:outline-2",  // outline color  "outline-blue-500 dark:outline-blue-500",]
    // Tremor Raw hasErrorInput [v0.0.1]
    export const hasErrorInput = [  // base  "ring-2",  // border color  "border-red-500 dark:border-red-700",  // ring color  "ring-red-200 dark:ring-red-700/30",]

    Next, we add the chart utilities. Add a new chartUtils.ts file and paste the following code into this file.

    // Tremor Raw chartColors [v0.1.0]
    export type ColorUtility = "bg" | "stroke" | "fill" | "text"
    export const chartColors = {  blue: {    bg: "bg-blue-500",    stroke: "stroke-blue-500",    fill: "fill-blue-500",    text: "text-blue-500",  },  emerald: {    bg: "bg-emerald-500",    stroke: "stroke-emerald-500",    fill: "fill-emerald-500",    text: "text-emerald-500",  },  violet: {    bg: "bg-violet-500",    stroke: "stroke-violet-500",    fill: "fill-violet-500",    text: "text-violet-500",  },  amber: {    bg: "bg-amber-500",    stroke: "stroke-amber-500",    fill: "fill-amber-500",    text: "text-amber-500",  },  gray: {    bg: "bg-gray-500",    stroke: "stroke-gray-500",    fill: "fill-gray-500",    text: "text-gray-500",  },  cyan: {    bg: "bg-cyan-500",    stroke: "stroke-cyan-500",    fill: "fill-cyan-500",    text: "text-cyan-500",  },  pink: {    bg: "bg-pink-500",    stroke: "stroke-pink-500",    fill: "fill-pink-500",    text: "text-pink-500",  },  lime: {    bg: "bg-lime-500",    stroke: "stroke-lime-500",    fill: "fill-lime-500",    text: "text-lime-500",  },  fuchsia: {    bg: "bg-fuchsia-500",    stroke: "stroke-fuchsia-500",    fill: "fill-fuchsia-500",    text: "text-fuchsia-500",  },} as const satisfies {  [color: string]: {    [key in ColorUtility]: string  }}
    export type AvailableChartColorsKeys = keyof typeof chartColors
    export const AvailableChartColors: AvailableChartColorsKeys[] = Object.keys(  chartColors,) as Array<AvailableChartColorsKeys>
    export const constructCategoryColors = (  categories: string[],  colors: AvailableChartColorsKeys[],): Map<string, AvailableChartColorsKeys> => {  const categoryColors = new Map<string, AvailableChartColorsKeys>()  categories.forEach((category, index) => {    categoryColors.set(category, colors[index % colors.length])  })  return categoryColors}
    export const getColorClassName = (  color: AvailableChartColorsKeys,  type: ColorUtility,): string => {  const fallbackColor = {    bg: "bg-gray-500",    stroke: "stroke-gray-500",    fill: "fill-gray-500",    text: "text-gray-500",  }  return chartColors[color]?.[type] ?? fallbackColor[type]}
    // Tremor Raw getYAxisDomain [v0.0.0]
    export const getYAxisDomain = (  autoMinValue: boolean,  minValue: number | undefined,  maxValue: number | undefined,) => {  const minDomain = autoMinValue ? "auto" : minValue ?? 0  const maxDomain = maxValue ?? "auto"  return [minDomain, maxDomain]}
    // Tremor Raw hasOnlyOneValueForKey [v0.1.0]
    export function hasOnlyOneValueForKey(  array: any[],  keyToCheck: string,): boolean {  const val: any[] = []
      for (const obj of array) {    if (Object.prototype.hasOwnProperty.call(obj, keyToCheck)) {      val.push(obj[keyToCheck])      if (val.length > 1) {        return false      }    }  }
      return true}
    
  7. 7

    Notes on your project structure

    When adding components, we recommend adding them to a components directory inside /src. Here is an example on how we'd structure our app:

    .├── src│   ├── app│   │   ├── favicon.ico│   │   ├── globals.css│   │   ├── layout.tsx│   │   └── page.tsx│   ├── components│   │   ├── Accordion.tsx│   │   ├── Badge.tsx│   │   └── ...│   └── lib│       ├── utils.ts│       └── chartUtils.ts├── package-lock.json├── package.json├── postcss.config.js└── tsconfig.json

Dark mode usage:

For all examples, we use bg-gray-950 as the overall background color. You can add this to your <html className="dark:bg-gray-950"> tag.

Font smoothing (antialiasing):

On our website, we apply font smoothing and recommend you do the same. Simply add the antialiased utility to the HTML tag <html className="antialiased">.