Langsung ke konten
KamusNgoding
Pemula React 7 menit baca

Cara Styling Komponen di React

#react #css #styling #beginner

Cara Styling Komponen di React

Pendahuluan

Bayangkan kamu sedang membangun sebuah rumah. Strukturnya sudah berdiri — dinding, atap, pintu sudah ada. Tapi tanpa cat, furnitur, dan dekorasi, rumah itu terasa kosong dan tidak nyaman. Begitu pula dengan komponen React: tanpa styling, UI kamu hanya berupa teks dan elemen HTML polos yang membosankan.

Styling di React berbeda dari HTML biasa. Ada banyak cara yang bisa dipilih — dari CSS tradisional, CSS Modules, hingga CSS-in-JS modern. Masing-masing punya kelebihan dan kapan waktu yang tepat untuk menggunakannya.

Di artikel ini, kita akan belajar berbagai metode styling di React dari yang paling sederhana hingga yang lebih advanced, lengkap dengan contoh kode yang bisa langsung kamu coba. Jika kamu belum familiar dengan konsep dasar React, ada baiknya baca dulu artikel tentang Pengenalan React: Membuat Komponen Pertamamu sebelum melanjutkan.


Styling dengan CSS Biasa dan Inline Styles

CSS Biasa (External Stylesheet)

Cara paling klasik: buat file .css terpisah, lalu import ke komponen React kamu.

// src/components/Button.jsx
import './Button.css';

function Button({ label }) {
  return <button className="btn-primary">{label}</button>;
}

export default Button;
/* src/components/Button.css */
.btn-primary {
  background-color: #0070f3;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 16px;
}

.btn-primary:hover {
  background-color: #0051a2;
}

Perhatian penting: Di React, gunakan className bukan class. Ini karena class adalah kata kunci JavaScript yang sudah dipakai untuk membuat kelas. React menggunakan className agar tidak bentrok.

Inline Styles

Inline styles di React ditulis sebagai objek JavaScript, bukan string seperti di HTML biasa.

function Alert({ message, type }) {
  const alertStyle = {
    padding: '12px 16px',
    borderRadius: '4px',
    backgroundColor: type === 'success' ? '#d4edda' : '#f8d7da',
    color: type === 'success' ? '#155724' : '#721c24',
    marginBottom: '16px',
  };

  return <div style={alertStyle}>{message}</div>;
}

export default Alert;

Perhatikan beberapa hal:

  • Property CSS ditulis dengan camelCase: backgroundColor, bukan background-color
  • Nilai pixel bisa ditulis sebagai angka: padding: 12 sama dengan padding: '12px'
  • Sangat berguna untuk styling dinamis berdasarkan props atau state

Menggunakan CSS Modules untuk Local Scope

Masalah dengan CSS Biasa

CSS biasa bersifat global — artinya, class .btn-primary yang kamu buat di Button.css bisa bentrok dengan class yang sama di file lain. Ini masalah besar saat proyekmu membesar.

CSS Modules: Solusinya

CSS Modules membuat setiap class menjadi unik secara otomatis. Strukturnya sama seperti CSS biasa, tapi nama file diakhiri .module.css.

/* src/components/Card.module.css */
.card {
  background: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  padding: 20px;
  max-width: 320px;
}

.cardTitle {
  font-size: 20px;
  font-weight: bold;
  margin-bottom: 8px;
  color: #333;
}

.cardContent {
  color: #666;
  line-height: 1.6;
}
// src/components/Card.jsx
import styles from './Card.module.css';

function Card({ title, content }) {
  return (
    <div className={styles.card}>
      <h2 className={styles.cardTitle}>{title}</h2>
      <p className={styles.cardContent}>{content}</p>
    </div>
  );
}

export default Card;

Di balik layar, React akan mengubah styles.card menjadi nama unik seperti Card_card__xK3p9 — sehingga tidak akan pernah bentrok dengan class dari komponen lain.

Menggabungkan Beberapa Class

import styles from './Button.module.css';

function Button({ label, variant, disabled }) {
  const buttonClass = [
    styles.button,
    styles[variant],           // 'primary', 'secondary', dll
    disabled ? styles.disabled : '',
  ].join(' ');

  return (
    <button className={buttonClass} disabled={disabled}>
      {label}
    </button>
  );
}

export default Button;

Mengenal CSS-in-JS dan Utility-First CSS

CSS-in-JS: Styled Components

Library styled-components memungkinkan kamu menulis CSS langsung di dalam file JavaScript menggunakan tagged template literals.

npm install styled-components
// src/components/StyledButton.jsx
import styled from 'styled-components';

const StyledButton = styled.button`
  background: ${(props) => (props.primary ? '#0070f3' : 'white')};
  color: ${(props) => (props.primary ? 'white' : '#0070f3')};
  padding: 10px 20px;
  border: 2px solid #0070f3;
  border-radius: 6px;
  cursor: pointer;
  font-size: 16px;

  &:hover {
    opacity: 0.85;
  }
`;

function App() {
  return (
    <div>
      <StyledButton primary>Tombol Utama</StyledButton>
      <StyledButton>Tombol Sekunder</StyledButton>
    </div>
  );
}

export default App;

Kelebihan styled-components: styling mengikuti komponen, mudah dibuat dinamis berdasarkan props, dan mendukung semua fitur CSS termasuk pseudo-class dan media queries.

CSS-in-JS: Emotion

Emotion adalah alternatif CSS-in-JS yang populer, lebih ringan, dan performa runtime-nya lebih baik dibandingkan styled-components.

npm install @emotion/react @emotion/styled
// src/components/EmotionCard.jsx
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import styled from '@emotion/styled';

const cardStyle = css`
  background: white;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  max-width: 320px;
`;

const Title = styled.h2`
  font-size: 20px;
  color: #333;
  margin-bottom: 8px;
`;

const Content = styled.p`
  color: #666;
  line-height: 1.6;
`;

function EmotionCard({ title, content }) {
  return (
    <div css={cardStyle}>
      <Title>{title}</Title>
      <Content>{content}</Content>
    </div>
  );
}

export default EmotionCard;

Emotion mendukung dua cara penulisan: menggunakan css prop langsung di elemen, atau menggunakan styled API yang mirip dengan styled-components.

Utility-First CSS: Tailwind CSS

Tailwind menggunakan class-class kecil yang masing-masing melakukan satu hal. Seperti lego — kamu gabungkan class kecil untuk membangun tampilan yang kompleks tanpa menulis CSS sama sekali.

npm install tailwindcss @tailwindcss/vite
// src/components/ProfileCard.jsx
function ProfileCard({ name, role, avatar }) {
  return (
    <div className="bg-white rounded-xl shadow-md p-6 max-w-sm mx-auto">
      <img
        src={avatar}
        alt={name}
        className="w-16 h-16 rounded-full mx-auto mb-4 object-cover"
      />
      <h2 className="text-xl font-bold text-center text-gray-800">{name}</h2>
      <p className="text-center text-gray-500 mt-1">{role}</p>
    </div>
  );
}

export default ProfileCard;

Jika kamu ingin membangun aplikasi berskala besar seperti platform marketplace, Tailwind sangat populer karena mempercepat pengembangan UI secara signifikan tanpa harus berpindah-pindah file.


Perbandingan Metode Styling

MetodeScopeDinamisSetupCocok untuk
CSS BiasaGlobalTerbatasTidak perluProyek kecil, prototipe
Inline StylesPer elemenSangat baikTidak perluStyling berbasis data/state
CSS ModulesLokalBaikMinimalProyek menengah ke atas
Styled ComponentsLokalSangat baikInstall libraryKomponen yang sangat dinamis
EmotionLokalSangat baikInstall libraryPerforma tinggi + TypeScript
Tailwind CSSUtilityBaikSetup configTim besar, UI cepat

Contoh Kasus Nyata: Membangun Kartu Profil

Mari gabungkan semua yang sudah dipelajari untuk membangun komponen kartu profil yang lengkap menggunakan CSS Modules.

/* src/components/ProfileCard.module.css */
.container {
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  padding: 24px;
  max-width: 300px;
  text-align: center;
  transition: transform 0.2s ease;
}

.container:hover {
  transform: translateY(-4px);
}

.avatar {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  object-fit: cover;
  border: 3px solid #0070f3;
  margin-bottom: 12px;
}

.name {
  font-size: 20px;
  font-weight: 700;
  color: #1a1a2e;
  margin: 0 0 4px;
}

.role {
  font-size: 14px;
  color: #666;
  margin: 0 0 16px;
}

.badge {
  display: inline-block;
  padding: 4px 12px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 600;
}

.badgeFrontend {
  background: #e3f2fd;
  color: #1565c0;
}

.badgeBackend {
  background: #e8f5e9;
  color: #2e7d32;
}
// src/components/ProfileCard.jsx
import styles from './ProfileCard.module.css';

function ProfileCard({ name, role, avatar, specialty }) {
  const badgeClass = specialty === 'frontend'
    ? styles.badgeFrontend
    : styles.badgeBackend;

  return (
    <div className={styles.container}>
      <img src={avatar} alt={name} className={styles.avatar} />
      <h2 className={styles.name}>{name}</h2>
      <p className={styles.role}>{role}</p>
      <span className={`${styles.badge} ${badgeClass}`}>
        {specialty}
      </span>
    </div>
  );
}

export default ProfileCard;
// src/App.jsx
import ProfileCard from './components/ProfileCard';

function App() {
  return (
    <div style={{ padding: '40px', display: 'flex', gap: '20px' }}>
      <ProfileCard
        name="Budi Santoso"
        role="Software Engineer"
        avatar="/images/budi.jpg"
        specialty="frontend"
      />
      <ProfileCard
        name="Dewi Rahayu"
        role="Backend Developer"
        avatar="/images/dewi.jpg"
        specialty="backend"
      />
    </div>
  );
}

export default App;

Teknik penggabungan class dengan template literal (`${styles.badge} ${badgeClass}`) ini sangat sering digunakan. Untuk penanganan yang lebih kompleks, kamu bisa menggunakan library clsx atau classnames. Pola serupa juga banyak dipakai saat menangani interaksi pengguna — kamu bisa pelajari lebih lanjut di artikel tentang Menguasai Event Handler di React untuk memperkuat pemahaman kamu tentang interaksi dinamis yang sering dipadukan dengan styling.


Troubleshooting: Error yang Sering Muncul

Styling Tidak Muncul Setelah Import CSS

Penyebab: File CSS tidak diimport dengan benar, atau nama class salah karena typo. Sering terjadi saat memindahkan file tanpa mengupdate path import.

Solusi:

// ❌ Path yang salah
import styles from './card.module.css';   // huruf besar/kecil berbeda

// ✅ Path yang benar (sesuai nama file)
import styles from './Card.module.css';

// ✅ Cek nama class (case-sensitive!)
<div className={styles.cardTitle}>   {/* bukan styles.CardTitle */}

className vs class — Komponen Menampilkan Warning di Console

Penyebab: Menggunakan atribut class seperti di HTML biasa, padahal React menggunakan className. React akan menampilkan warning: “Invalid DOM property class. Did you mean className?”

Solusi:

// ❌ Salah — format HTML biasa
<div class="container">Konten</div>

// ✅ Benar — gunakan className di React
<div className="container">Konten</div>

// ✅ Dengan CSS Modules
<div className={styles.container}>Konten</div>

Inline Style Tidak Bekerja karena Format Salah

Penyebab: Menulis inline style sebagai string (seperti di HTML), bukan sebagai objek JavaScript. React akan melempar error: “The style prop expects a mapping from style properties to values, not a string.”

Solusi:

// ❌ Salah — ini format HTML, bukan React
<div style="background-color: red; font-size: 16px;">Konten</div>

// ✅ Benar — gunakan objek JavaScript dengan camelCase
<div style={{ backgroundColor: 'red', fontSize: '16px' }}>Konten</div>

// ✅ Atau simpan di variabel terlebih dahulu
const myStyle = { backgroundColor: 'red', fontSize: '16px' };
<div style={myStyle}>Konten</div>

CSS Modules: Property undefined karena Nama Class Berbeda

Penyebab: Nama class di file .module.css dan di JSX tidak sama persis (case-sensitive). Menggunakan kebab-case di CSS Modules menyulitkan akses dari JavaScript.

Solusi:

/* Card.module.css */
.card-header { color: #333; }  /* ❌ Hindari kebab-case di CSS Modules */
.cardHeader { color: #333; }   /* ✅ Gunakan camelCase agar mudah diakses */
// JSX
<div className={styles['card-header']}>  {/* ⚠️ Bisa, tapi verbose */}
<div className={styles.cardHeader}>      {/* ✅ Lebih bersih */}

Styled Components: Error Cannot read properties of undefined

Penyebab: Mengakses props di dalam template literal styled-components sebelum komponen menerima prop tersebut, atau prop tidak diteruskan ke komponen.

Solusi:

// ❌ Tanpa nilai default — bisa undefined
const Button = styled.button`
  background: ${(props) => props.primary ? '#0070f3' : 'white'};
`;

// ✅ Dengan nilai default menggunakan nullish coalescing
const Button = styled.button`
  background: ${(props) => props.primary ?? false ? '#0070f3' : 'white'};
`;

// ✅ Atau gunakan defaultProps
Button.defaultProps = {
  primary: false,
};

Pertanyaan yang Sering Diajukan

Apa perbedaan CSS Modules dengan CSS biasa?

CSS Modules menghasilkan nama class yang unik secara otomatis sehingga tidak akan bentrok dengan class lain di aplikasi. CSS biasa bersifat global — class yang sama di dua file berbeda bisa saling menimpa satu sama lain. Untuk proyek kecil, CSS biasa cukup; untuk proyek besar dengan banyak komponen, CSS Modules jauh lebih aman dan mudah di-maintain.

Kapan sebaiknya menggunakan inline styles?

Inline styles paling cocok untuk styling yang benar-benar dinamis — misalnya warna yang bergantung pada nilai dari database, posisi elemen yang dihitung saat runtime, atau animasi berbasis state. Untuk styling yang statis atau berulang, lebih baik gunakan CSS biasa atau CSS Modules karena lebih mudah dikelola dan performa browser lebih optimal.

Apa perbedaan styled-components dengan Emotion?

Keduanya adalah library CSS-in-JS dengan API yang sangat mirip. Perbedaan utamanya: Emotion memiliki bundle size yang lebih kecil dan performa runtime yang sedikit lebih baik, serta dukungan TypeScript yang lebih kuat. Styled-components memiliki ekosistem yang lebih besar dan komunitas yang lebih lama. Untuk proyek baru, Emotion sering menjadi pilihan yang lebih direkomendasikan.

Apakah bisa menggunakan Tailwind CSS bersama CSS Modules?

Ya, keduanya bisa digunakan bersamaan dalam satu proyek. Umumnya Tailwind digunakan untuk layout dan spacing (padding, margin, flexbox, grid), sementara CSS Modules untuk komponen yang punya logika styling kompleks atau animasi khusus. Tidak ada aturan ketat — sesuaikan dengan kebutuhan dan preferensi tim kamu.

Apakah inline styles di React mendukung pseudo-class seperti :hover?

Tidak secara langsung. Inline styles React tidak mendukung :hover, :focus, :active, atau media queries. Untuk kebutuhan ini, gunakan CSS biasa, CSS Modules, atau library seperti styled-components dan Emotion yang mendukung semua fitur CSS secara penuh termasuk pseudo-class dan media queries.


Kesimpulan

Kamu sudah mempelajari lima cara utama untuk styling komponen React:

  1. CSS Biasa — sederhana, cocok untuk proyek kecil atau komponen yang tidak kompleks
  2. Inline Styles — fleksibel untuk styling dinamis berdasarkan props atau state
  3. CSS Modules — solusi terbaik untuk menghindari konflik nama class di proyek yang lebih besar
  4. CSS-in-JS (styled-components & Emotion) — powerful untuk komponen yang sangat dinamis dan butuh encapsulation penuh
  5. Utility-First CSS (Tailwind) — cepat dan konsisten, sangat populer untuk tim besar

Tidak ada satu cara yang paling benar — setiap pendekatan punya tempat dan waktunya sendiri. Untuk pemula, mulailah dengan CSS Modules karena mudah dipahami dan sudah menyelesaikan sebagian besar masalah umum. Selamat bereksperimen dengan styling di React — semakin sering kamu praktik dengan berbagai metode, semakin tajam insting kamu dalam memilih pendekatan yang tepat untuk setiap situasi!

Artikel Terkait