Sabtu, 23 November 2024

Upgrade Justd ke Tailwind CSS v4

Dalam aritkel ini kita akan belajar untuk memigrasikan Justd dari Tailwind CSS v3 ke v4. Pelajari langkah-langkah mudah dan penyesuaian penting untuk transisi yang mulus.

Tailwind CSS
React

Intro

Artikel ini memberikan panduan lengkap tentang cara memigrasikan Justd, yang secara default menggunakan Tailwind CSS v3, ke versi terbaru, yaitu Tailwind CSS v4, untuk memastikan transisi berjalan lancar.

Upgrade

Pertama-tama, penting untuk diketahui bahwa Tailwind CSS menyediakan alat CLI codemod, npx @tailwindcss/upgrade@next, yang dapat digunakan untuk meningkatkan proyek Anda saat ini. Namun, jika Anda mengalami masalah saat menjalankannya, jangan khawatir—saya akan membimbing Anda langkah demi langkah melalui proses ini.

Selain itu, Anda juga dapat mengunjungi dokumentasi Tailwind CSS v4 beta untuk memastikan Anda sepenuhnya memahami perubahan yang diperlukan pada framework yang sedang Anda gunakan. Dalam panduan ini, saya akan fokus pada contoh menggunakan Vite dan Next.js.

Vite

npm install tailwindcss@next @tailwindcss/vite@next

Kemudian, di file vite.config.ts Anda, tambahkan plugin yang diperlukan seperti berikut:

import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
  plugins: [
    tailwindcss()
  ],
});

Next.js

Untuk Next.js, Anda perlu menginstal plugin PostCSS yang disediakan oleh Tailwind CSS dengan menjalankan perintah berikut.

npm install tailwindcss@next @tailwindcss/postcss@next

Buka file postcss.config.mjs Anda, dan tambahkan plugin tersebut seperti ini.

export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
};

Setelah menyelesaikan langkah-langkah sebelumnya, kita sekarang dapat melanjutkan ke pengaturan.

Default Justd CSS

Pertama, saya akan mengasumsikan bahwa Anda sudah menginstal Justd, yang secara default menggunakan Tailwind CSS v3. Biasanya, CSS Anda akan terlihat seperti ini:

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
    --light: 223.81 0% 98%;
    --dark: 239.95 9% 6%;
    --bg: 0 0% 100%;
    --fg: 239.93 9% 4%;
    --primary: 216.77 100% 50%;
    --primary-fg: 0 0% 100%;
    --secondary: 240 4% 96%;
    --secondary-fg: 240.01 6% 10%;
    --tertiary: 0 0% 100%;
    --tertiary-fg: 240 4% 16%;
    --overlay: 0 0% 100%;
    --overlay-fg: 239.93 9% 4%;
    --muted: 240 4% 96%;
    --muted-fg: 240.01 4% 46%;
    --accent: 216.77 100% 50%;
    --accent-fg: 0 0% 100%;
    --accent-subtle: 216.92 99% 97%;
    --accent-subtle-fg: 216.74 100% 40%;
    --success: 161.17 91% 31%;
    --success-fg: 151.77 82% 96%;
    --info: 205.77 100% 50%;
    --info-fg: 0 0% 100%;
    --danger: 0.01 72% 51%;
    --danger-fg: 360 86% 97%;
    --warning: 43.2 96% 56.99%;
    --warning-fg: 20.91 91% 14.1%;
    --border: 240 6% 90%;
    --input: 240 6% 90%;
    --ring: var(--primary);
    --toggle: 240.01 5% 84%;
    --radius: 0.5rem;
    --primary-chart: 216.74 100% 45%;
    --secondary-chart: 219.83 100% 77%;
    --tertiary-chart: 216.01 92% 60%;
    --highlight-chart: 210 98% 78%;
    --accent-chart: 210 98% 78%;
  }

  .dark {
    --bg: 0 0% 0%;
    --fg: 223.81 0% 98%;
    --primary: 216.04 98% 52%;
    --primary-fg: 0 0% 100%;
    --secondary: 239.99 6% 11%;
    --secondary-fg: 223.81 0% 98%;
    --tertiary: 240.02 10% 6%;
    --tertiary-fg: 239.99 4% 96%;
    --accent: 216.04 98% 52%;
    --accent-fg: 0 0% 100%;
    --accent-subtle: 215.99 94% 6%;
    --accent-subtle-fg: 204.92 100% 77%;
    --overlay: 240.03 6% 6%;
    --overlay-fg: 223.81 0% 98%;
    --muted: 239.95 3% 16%;
    --muted-fg: 240.01 5% 65%;
    --info: 205.77 100% 50%;
    --info-fg: 0 0% 100%;
    --success: 161.17 91% 31%;
    --success-fg: 151.77 82% 96%;
    --ring: var(--primary);
    --toggle: 239.99 5% 26%;
    --border: 240.01 7.1% 15%;
    --input: 239.95 3% 16%;
    --primary-chart: 221.19 83% 53%;
    --secondary-chart: 211.99 95% 68%;
    --tertiary-chart: 216.01 92% 60%;
    --highlight-chart: 210 98% 78%;
    --accent-chart: 212 96% 87%;
  }
}

@layer base {
  html {
    @apply scroll-smooth;
  }

  * {
    @apply border-border;
    font-feature-settings: "cv11", "ss01";
    font-variation-settings: "opsz" 850;
    text-rendering: optimizeLegibility;
    scrollbar-width: thin;
  }

  body {
    @apply bg-bg text-fg;
  }

  /* dark mode */
  .dark {
    scrollbar-width: thin;

    @media (prefers-color-scheme: dark) {
      * {
        scrollbar-width: thin;
      }
    }
  }

  /* Chrome, Edge, and Safari */
  *::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }

  *::-webkit-scrollbar-track {
    background: transparent;
    border-radius: 5px;
  }

  *::-webkit-scrollbar-thumb {
    @apply bg-muted;
    border-radius: 14px;
    border: 3px solid transparent;
  }
}

Sekarang, dengan versi baru Tailwind CSS, pembaruan berikut akan diterapkan.

@import 'tailwindcss';

@plugin 'tailwindcss-animate'

@variant dark (&:is(.dark *));

@theme {
  --font-sans: var(--font-sans), sans-serif;
  --font-mono: var(--font-mono), monospace;

  --color-light: var(--light);
  --color-dark: var(--dark);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --color-toggle: var(--toggle);
  --color-bg: var(--bg);
  --color-fg: var(--fg);
  --color-primary: var(--primary);
  --color-primary-fg: var(--primary-fg);

  --color-secondary: var(--secondary);
  --color-secondary-fg: var(--secondary-fg);
  --color-tertiary: var(--tertiary);
  --color-tertiary-fg: var(--tertiary-fg);
  --color-accent: var(--accent);
  --color-accent-fg: var(--accent-fg);
  --color-accent-subtle: var(--accent-subtle);
  --color-accent-subtle-fg: var(--accent-subtle-fg);
  --color-success: var(--success);
  --color-success-fg: var(--success-fg);
  --color-info: var(--info);
  --color-info-fg: var(--info-fg);
  --color-danger: var(--danger);
  --color-danger-fg: var(--danger-fg);
  --color-warning: var(--warning);
  --color-warning-fg: var(--warning-fg);
  --color-muted: var(--muted);
  --color-muted-fg: var(--muted-fg);

  --color-overlay: var(--overlay);
  --color-overlay-fg: var(--overlay-fg);

  --radius-3xl: calc(var(--radius) + 7.5px);
  --radius-2xl: calc(var(--radius) + 5px);
  --radius-xl: calc(var(--radius) + 2.5px);
  --radius-lg: calc(var(--radius));
  --radius-md: calc(var(--radius) - 2.5px);
  --radius-sm: calc(var(--radius) - 5px);
}

@utility container {
  margin-inline: auto;
  padding-inline: 2rem;
  @media (width >= theme(--breakpoint-sm)) {
    max-width: none;
  }
  @media (width >= 1400px) {
    max-width: 1400px;
  }
}

@layer base {
  *,
  ::after,
  ::before,
  ::backdrop,
  ::file-selector-button {
    border-color: var(--color-gray-200, currentColor);
  }
}

@layer base {
  :root {
    --light: oklch(0.985 0 0);
    --dark: oklch(0.141 0.005 285.823);
    --bg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --fg: oklch(0.141 0.005 285.823);
    --primary: oklch(0.546 0.245 262.881);
    --primary-fg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --secondary: oklch(0.967 0.001 286.375);
    --secondary-fg: oklch(0.141 0.005 285.823);
    --tertiary: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --tertiary-fg: oklch(0.141 0.005 285.823);
    --overlay: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --overlay-fg: oklch(0.141 0.005 285.823);
    --muted: oklch(0.967 0.001 286.375);
    --muted-fg: oklch(0.552 0.016 285.938);
    --accent: oklch(0.546 0.245 262.881);
    --accent-fg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --accent-subtle: oklch(97.05% 0.01418224665972208 254.6041641690868);
    --accent-subtle-fg: 216.74 100% 40%;
    --success: oklch(0.596 0.145 163.225);
    --success-fg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --info: oklch(0.588 0.158 241.966);
    --info-fg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --danger: oklch(0.577 0.245 27.325);
    --danger-fg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --warning: oklch(0.681 0.162 75.834);
    --warning-fg: oklch(0.987 0.026 102.212);
    --border: oklch(0.92 0.004 286.32);
    --input: oklch(0.92 0.004 286.32);
    --ring: oklch(0.546 0.245 262.881);
    --toggle: oklch(0.967 0.001 286.375);
    --radius: 0.5rem;
    --primary-chart: oklch(0.546 0.245 262.881);
    --secondary-chart: oklch(0.809 0.105 251.813);
    --tertiary-chart: oklch(0.623 0.214 259.815);
    --highlight-chart: oklch(0.882 0.059 254.128);
    --accent-chart: oklch(0.901 0.058 230.902);
  }

  .dark {
    --bg: oklch(0% 0 0);
    --fg: oklch(0.985 0 0);
    --primary: oklch(0.546 0.245 262.881);
    --primary-fg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --secondary: oklch(0.21 0.006 285.885);
    --secondary-fg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --tertiary: oklch(0.21 0.006 285.885);
    --tertiary-fg: 239.99 4% 96%;
    --accent: oklch(0.985 0 0);
    --accent-fg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --accent-subtle: oklch(23.19% 0.0222 269.09);
    --accent-subtle-fg: oklch(0.707 0.165 254.624);
    --overlay: oklch(0.21 0.006 285.885);
    --overlay-fg: oklch(0.985 0 0);
    --muted: oklch(0.274 0.006 286.033);
    --muted-fg: oklch(0.705 0.015 286.067);
    --info: oklch(0.588 0.158 241.966);
    --info-fg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --success: oklch(0.596 0.145 163.225);
    --success-fg: oklch(100% 3.5594404384177905e-8 106.37411429114086);
    --ring: oklch(0.546 0.245 262.881);
    --toggle: oklch(0.274 0.006 286.033);
    --border: oklch(0.274 0.006 286.033);
    --input: oklch(0.274 0.006 286.033);
    --primary-chart: oklch(0.546 0.245 262.881);
    --secondary-chart: oklch(0.809 0.105 251.813);
    --tertiary-chart: oklch(0.707 0.165 254.624);
    --highlight-chart: oklch(0.809 0.105 251.813);
    --accent-chart: oklch(0.882 0.059 254.128);
  }
}

@layer base {
  html {
    @apply scroll-smooth;
  }

  * {
    @apply border-border;
    font-feature-settings: "cv11", "ss01";
    font-variation-settings: "opsz" 850;
    text-rendering: optimizeLegibility;
    scrollbar-width: thin;
  }

  body {
    @apply bg-bg text-fg;
  }

  /* dark mode */
  .dark {
    scrollbar-width: thin;

    @media (prefers-color-scheme: dark) {
      * {
        scrollbar-width: thin;
      }
    }
  }

  /* Chrome, Edge, and Safari */
  *::-webkit-scrollbar {
    width: 8px;
    height: 8px;
  }

  *::-webkit-scrollbar-track {
    background: transparent;
    border-radius: 5px;
  }

  *::-webkit-scrollbar-thumb {
    @apply bg-muted;
    border-radius: 14px;
    border: 3px solid transparent;
  }
}

Ya, Anda benar! Ada cukup banyak penyesuaian yang perlu dilakukan, tetapi memang begitulah cara kerjanya.

Tailwind RAC (React Aria Component)

Anda mungkin bertanya-tanya tentang tailwindcss-react-aria-component (TRAC). Sayangnya, pada saat artikel ini ditulis, TRAC belum mendukung Tailwind CSS v4. Namun, saya yakin pembaruan akan segera dirilis. Sementara itu, berikut adalah beberapa hal yang dapat Anda lakukan untuk beradaptasi:

  • Utilitas seperti exiting telah diubah menjadi data-exiting.
  • Untuk variabel, sintaks seperti bg-[--button-border] kini diperbarui menjadi bg-(--button-border).
  • Jika Anda menggunakan popover atau komponen serupa, perubahan seperti placement-left sekarang menjadi data-[placement=left].

Ini adalah beberapa fitur dan pembaruan sintaks baru yang perlu Anda terapkan untuk memastikan kompatibilitas.