Perbedaan paling terlihat antara stylesheet biasa dan component library terletak pada sumber nilainya. Pada halaman tunggal, warna dan jarak boleh ditulis langsung; pada library yang dipakai ulang lintas halaman, setiap nilai yang lepas dari kelompoknya menjadi utang konsistensi yang dibayar di kemudian hari. Karena itu Bagian 1 proyek Rakit UI tidak dimulai dari komponen, melainkan dari design tokens: dua lapis token warna — primitif dan semantik — plus skala spasi, radius, bayangan, dan tipografi. Komponen pertama kita, badge, sekaligus menjadi bukti bahwa lapisan token sudah siap dikonsumsi.
Tujuan Bagian dan Prasyarat #
Di akhir bagian ini styles/komponen.css memuat fondasi berikut:
- Token primitif: sembilan tingkat skala netral
--zinc-*, tiga tingkat skala primer--teal-*, dan dua warna status. - Token semantik
--color-*: latar, permukaan, teks, teks redup, garis, primer, primer hover, teks di atas primer, primer lunak, sukses, dan bahaya. - Skala spasi
--space-*enam tingkat, tiga token radius, dua token bayangan, dan lima ukuran teks. - Reset minimal, gaya
body, wadah.wadah, dan komponen.badgesebagai konsumen pertama.
Teori di balik pola ini dibahas pada chapter Design Tokens dan Custom Properties ; sudut pandang sistem desainnya ada pada Design Tokens dan Color Palettes . Kita tidak mengulangnya di sini, hanya memakainya dalam bentuk paling praktis.
Menulis Dua Lapis Token #
Tulis blok berikut sebagai bagian pertama styles/komponen.css. Token primitif menyimpan nilai mentah; token semantik menyimpan peran. Nama token memakai bahasa Inggris ala pustaka publik karena library ini berlatih pola penamaan yang umum dijumpai di ekosistem open source.
:root {
/* Token primitif: skala netral zinc */
--zinc-50: #fafafa;
--zinc-200: #e4e4e7;
--zinc-400: #a1a1aa;
--zinc-600: #52525b;
--zinc-800: #27272a;
--zinc-900: #18181b;
/* Token primitif: skala teal untuk warna primer */
--teal-500: #14b8a6;
--teal-600: #0d9488;
--teal-700: #0f766e;
/* Token primitif: warna status */
--hijau-600: #16a34a;
--merah-600: #dc2626;
/* Token semantik: peran, bukan warna */
--color-bg: #fafafa;
--color-surface: #ffffff;
--color-text: #18181b;
--color-muted: #52525b;
--color-border: #e4e4e7;
--color-primary: #0d9488;
--color-primary-hover: #0f766e;
--color-on-primary: #ffffff;
--color-primary-soft: rgb(13 148 136 / 10%);
--color-success: #16a34a;
--color-danger: #dc2626;
/* Skala spasi (kelipatan 4px) */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-6: 24px;
--space-8: 32px;
/* Radius */
--radius-sm: 6px;
--radius-md: 10px;
--radius-full: 999px;
/* Bayangan */
--shadow-sm: 0 1px 2px rgb(0 0 0 / 6%);
--shadow-md: 0 4px 12px rgb(0 0 0 / 10%);
/* Tipografi */
--font-sans: system-ui, sans-serif;
--font-mono: ui-monospace, monospace;
--text-xs: 12px;
--text-sm: 14px;
--text-base: 16px;
--text-lg: 20px;
--text-xl: 24px;
}
* {
margin: 0;
box-sizing: border-box;
}
body {
font-family: var(--font-sans);
font-size: var(--text-base);
line-height: 1.5;
color: var(--color-text);
background-color: var(--color-bg);
}
.wadah {
max-width: 960px;
margin: 0 auto;
padding: var(--space-6);
}
.badge {
display: inline-flex;
align-items: center;
column-gap: var(--space-1);
padding: var(--space-1) var(--space-2);
border-radius: var(--radius-full);
background-color: var(--color-primary-soft);
color: var(--color-primary);
font-size: var(--text-sm);
font-weight: 500;
}Markup pembuktinya satu badge di dalam wadah:
<body>
<main class="wadah">
<span class="badge">Stabil v1.0</span>
</main>
</body>Hasil di Browser:
Badge tampil sebagai pil berlatar rgba(13, 148, 136, 0.1) —
primer dengan alpha 10% — dengan teks rgb(13, 148, 136) dan
radius 999px. Body berlatar rgb(250, 250, 250) dengan teks
rgb(24, 24, 27), dan wadah dokumen terukur maksimal 960px
dengan padding 24px di setiap sisi.Bedah Lapisan Token #
- Lapis primitif: nama seperti
--zinc-600hanya menyebut skala dan tingkat, tanpa maksud penggunaan. Lapis ini boleh tumbuh tanpa mengubah komponen apa pun. - Lapis semantik:
--color-primarymenjawab “warna aksi utama”, bukan “teal”. Kami menulis nilainya sebagai literal (#0d9488), bukanvar(--teal-600), sebagai konvensi sadar: memotong ketergantungan antarlapis membuat kedua lapis bisa diperbaiki sendiri-sendiri, dan hasil computed pada DevTools langsung terbaca. - Skala spasi: angka pada nama adalah langkah skala, bukan piksel —
--space-6bernilai 24px karena kelipatan 4px. Langkah 5 dan 7 sengaja tidak ada agar pilihan jarak selalu terbatas. .badgesebagai konsumen: setiap deklarasi merujukvar(); satu-satunya nilai literal tersisa adalahfont-weight: 500. Bentuk pil lahir dari--radius-fullbernilai 999px, trik yang sama dengan badge portofolio.column-gappada badge:inline-flexdipilih agar badge bisa menampung ikon di Bagian 4 tanpa mengubah geometri; jarak ikon-teks diatur--space-1.
Perhatikan bahwa tidak ada komponen yang menulis nilai warna atau jarak sendiri. Saat warna primer berubah, kita mengubah satu token — bukan mencari-cari #0d9488 di seluruh file.
Uji Bagian Ini #
Halaman uji bagian ini tersedia di /tests/css/proyek/component-library/design-tokens.html
, dengan spesifikasi lengkap pada tests/design-tokens.spec.js. Halaman uji juga membuktikan bahwa token terbaca langsung dari computed style elemen html:
| Elemen | Properti | Diharapkan |
|---|---|---|
html | --color-primary | #0d9488 |
html | --space-6 | 24px |
html | --radius-md | 10px |
html | --text-base | 16px |
body | background-color | rgb(250, 250, 250) |
body | color | rgb(24, 24, 27) |
.wadah | max-width | 960px |
.wadah | padding-top | 24px |
.badge | background-color | rgba(13, 148, 136, 0.1) |
.badge | color | rgb(13, 148, 136) |
.badge | border-radius | 999px |
.badge | font-size | 14px |
.badge | padding-top | 4px |
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
styles/komponen.css
Unduh berkas/* =========================================================
Proyek: Component Library (Rakit UI) — styles/komponen.css
File utuh library yang berkembang mengikuti empat bagian:
Bagian 1 (Design Tokens), Bagian 2 (Buttons dan Inputs),
Bagian 3 (Cards dan Navigation), Bagian 4 (Themes dan
Documentation). Komentar "Bagian N" menandai kelompok
aturan yang dibahas pada setiap bagian.
========================================================= */
/* Bagian 1: Design Tokens --------------------------------- */
:root {
/* Token primitif: skala netral zinc */
--zinc-50: #fafafa;
--zinc-100: #f4f4f5;
--zinc-200: #e4e4e7;
--zinc-400: #a1a1aa;
--zinc-500: #71717a;
--zinc-600: #52525b;
--zinc-700: #3f3f46;
--zinc-800: #27272a;
--zinc-900: #18181b;
/* Token primitif: skala teal untuk warna primer */
--teal-500: #14b8a6;
--teal-600: #0d9488;
--teal-700: #0f766e;
/* Token primitif: warna status */
--hijau-600: #16a34a;
--merah-600: #dc2626;
/* Token semantik: peran, bukan warna */
--color-bg: #fafafa;
--color-surface: #ffffff;
--color-text: #18181b;
--color-muted: #52525b;
--color-border: #e4e4e7;
--color-primary: #0d9488;
--color-primary-hover: #0f766e;
--color-on-primary: #ffffff;
--color-primary-soft: rgb(13 148 136 / 10%);
--color-success: #16a34a;
--color-danger: #dc2626;
/* Skala spasi (kelipatan 4px) */
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-6: 24px;
--space-8: 32px;
/* Radius */
--radius-sm: 6px;
--radius-md: 10px;
--radius-full: 999px;
/* Bayangan */
--shadow-sm: 0 1px 2px rgb(0 0 0 / 6%);
--shadow-md: 0 4px 12px rgb(0 0 0 / 10%);
/* Tipografi */
--font-sans: system-ui, sans-serif;
--font-mono: ui-monospace, monospace;
--text-xs: 12px;
--text-sm: 14px;
--text-base: 16px;
--text-lg: 20px;
--text-xl: 24px;
}
* {
margin: 0;
box-sizing: border-box;
}
body {
font-family: var(--font-sans);
font-size: var(--text-base);
line-height: 1.5;
color: var(--color-text);
background-color: var(--color-bg);
}
.wadah {
max-width: 960px;
margin: 0 auto;
padding: var(--space-6);
}
.badge {
display: inline-flex;
align-items: center;
column-gap: var(--space-1);
padding: var(--space-1) var(--space-2);
border-radius: var(--radius-full);
background-color: var(--color-primary-soft);
color: var(--color-primary);
font-size: var(--text-sm);
font-weight: 500;
}
/* Bagian 2: Buttons dan Inputs ---------------------------- */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
column-gap: var(--space-2);
padding: var(--space-2) var(--space-4);
font: inherit;
font-size: var(--text-base);
font-weight: 500;
border: 1px solid transparent;
border-radius: var(--radius-md);
cursor: pointer;
text-decoration: none;
transition: background-color 150ms ease, border-color 150ms ease,
color 150ms ease;
}
.btn-primer {
background-color: var(--color-primary);
color: var(--color-on-primary);
}
.btn-primer:hover {
background-color: var(--color-primary-hover);
}
.btn-kedua {
background-color: var(--color-surface);
color: var(--color-text);
border-color: var(--color-border);
}
.btn-hantu {
background-color: transparent;
color: var(--color-primary);
}
.btn-kecil {
padding: var(--space-1) var(--space-3);
font-size: var(--text-sm);
}
.btn-besar {
padding: var(--space-3) var(--space-6);
font-size: var(--text-lg);
}
.btn:disabled {
opacity: 0.55;
cursor: not-allowed;
}
.field {
display: grid;
row-gap: var(--space-2);
margin-bottom: var(--space-4);
}
.label {
font-size: var(--text-sm);
font-weight: 500;
}
.input {
width: 100%;
padding: var(--space-2) var(--space-3);
font: inherit;
color: var(--color-text);
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
}
.input:focus {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
border-color: var(--color-primary);
}
.input:disabled {
background-color: var(--color-bg);
color: var(--color-muted);
cursor: not-allowed;
}
.input-sukses {
border-color: var(--color-success);
}
.input-galat {
border-color: var(--color-danger);
}
.hint {
font-size: var(--text-xs);
color: var(--color-muted);
}
.hint-galat {
color: var(--color-danger);
}
/* Bagian 3: Cards dan Navigation -------------------------- */
.navbar {
position: sticky;
top: 0;
z-index: 100;
display: flex;
align-items: center;
justify-content: space-between;
column-gap: var(--space-4);
padding: var(--space-3) var(--space-6);
background-color: var(--color-surface);
border-bottom: 1px solid var(--color-border);
}
.nav-brand {
display: inline-flex;
align-items: center;
column-gap: var(--space-2);
font-size: var(--text-lg);
font-weight: 700;
color: var(--color-text);
text-decoration: none;
}
.nav-menu {
display: flex;
column-gap: var(--space-6);
list-style: none;
}
.nav-tautan {
color: var(--color-muted);
font-weight: 500;
text-decoration: none;
}
.nav-tautan:hover {
color: var(--color-primary);
}
.tabs {
display: flex;
column-gap: var(--space-2);
border-bottom: 1px solid var(--color-border);
}
.tab {
padding: var(--space-2) var(--space-3);
font: inherit;
font-size: var(--text-sm);
font-weight: 500;
color: var(--color-muted);
background-color: transparent;
border: none;
border-bottom: 2px solid transparent;
cursor: pointer;
}
.tab-aktif {
color: var(--color-primary);
border-bottom-color: var(--color-primary);
}
.grid-kartu {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-6);
margin-top: var(--space-6);
}
.card {
display: flex;
flex-direction: column;
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
overflow: hidden;
}
.card-shadow {
box-shadow: var(--shadow-md);
}
.card-badan {
display: grid;
row-gap: var(--space-2);
padding: var(--space-6);
}
.card-judul {
font-size: var(--text-lg);
font-weight: 600;
color: var(--color-text);
}
.card-teks {
font-size: var(--text-sm);
line-height: 1.5;
color: var(--color-muted);
}
.card-aksi {
display: flex;
column-gap: var(--space-2);
margin-top: var(--space-2);
}
/* Bagian 4: Themes dan Documentation ---------------------- */
[data-theme="gelap"] {
--color-bg: #18181b;
--color-surface: #27272a;
--color-text: #fafafa;
--color-muted: #a1a1aa;
--color-border: #3f3f46;
--color-primary-soft: rgb(20 184 166 / 16%);
--shadow-md: 0 4px 12px rgb(0 0 0 / 40%);
}
.tema-sampel {
padding: var(--space-6);
background-color: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
}
.docs-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: var(--space-4);
margin-top: var(--space-4);
}
.swatch {
display: block;
width: 64px;
height: 40px;
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
}
.swatch-nama {
font-family: var(--font-mono);
font-size: var(--text-xs);
color: var(--color-muted);
}
.contoh-kode {
padding: var(--space-3) var(--space-4);
background-color: var(--zinc-900);
color: var(--zinc-200);
font-family: var(--font-mono);
font-size: var(--text-sm);
border-radius: var(--radius-md);
overflow-x: auto;
}
tests/buttons-dan-inputs.spec.js
Unduh berkas// ============================================================
// Spesifikasi uji — Proyek: Component Library
// Bagian 2: Buttons dan Inputs
// ============================================================
// Berkas ini merangkum asersi yang diverifikasi oleh harness
// pada halaman uji:
// /tests/css/proyek/component-library/buttons-dan-inputs.html
// Setiap entri memasangkan elemen probe dengan properti CSS
// dan nilai computed yang diharapkan.
const asersi = [
// .btn-primer: geometri dari kelas dasar, warna dari token semantik.
{ elemen: ".btn-primer", properti: "background-color", diharapkan: "rgb(13, 148, 136)" },
{ elemen: ".btn-primer", properti: "color", diharapkan: "rgb(255, 255, 255)" },
{ elemen: ".btn-primer", properti: "padding-top", diharapkan: "8px" },
{ elemen: ".btn-primer", properti: "padding-left", diharapkan: "16px" },
{ elemen: ".btn-primer", properti: "border-radius", diharapkan: "10px" },
{ elemen: ".btn-primer", properti: "font-weight", diharapkan: "500" },
// .btn-besar: ukuran menimpa padding dan font-size kelas dasar.
{ elemen: ".btn-besar", properti: "font-size", diharapkan: "20px" },
{ elemen: ".btn-besar", properti: "padding-top", diharapkan: "12px" },
// .btn-kedua: permukaan putih dengan border dari token garis.
{ elemen: ".btn-kedua", properti: "background-color", diharapkan: "rgb(255, 255, 255)" },
{ elemen: ".btn-kedua", properti: "color", diharapkan: "rgb(24, 24, 27)" },
{ elemen: ".btn-kedua", properti: "border-top-color", diharapkan: "rgb(228, 228, 231)" },
// .btn:disabled: pseudo-class pada tombol dengan atribut disabled.
{ elemen: "button.btn[disabled]", properti: "opacity", diharapkan: "0.55" },
{ elemen: "button.btn[disabled]", properti: "cursor", diharapkan: "not-allowed" },
// .input: border, radius, dan tipografi dari token.
{ elemen: ".input", properti: "border-top-color", diharapkan: "rgb(228, 228, 231)" },
{ elemen: ".input", properti: "border-radius", diharapkan: "6px" },
{ elemen: ".input", properti: "font-size", diharapkan: "16px" },
{ elemen: ".input", properti: "background-color", diharapkan: "rgb(255, 255, 255)" },
// .input-galat: border berganti ke warna bahaya.
{ elemen: ".input-galat", properti: "border-top-color", diharapkan: "rgb(220, 38, 38)" },
// .hint: teks bantu kecil dan redup.
{ elemen: ".hint", properti: "font-size", diharapkan: "12px" },
{ elemen: ".hint", properti: "color", diharapkan: "rgb(82, 82, 91)" },
// .field: grid dengan jarak baris 8px dan pemisah antar field 16px.
{ elemen: ".field", properti: "row-gap", diharapkan: "8px" },
{ elemen: ".field", properti: "margin-bottom", diharapkan: "16px" },
];
tests/cards-dan-navigation.spec.js
Unduh berkas// ============================================================
// Spesifikasi uji — Proyek: Component Library
// Bagian 3: Cards dan Navigation
// ============================================================
// Berkas ini merangkum asersi yang diverifikasi oleh harness
// pada halaman uji:
// /tests/css/proyek/component-library/cards-dan-navigation.html
// Setiap entri memasangkan elemen probe dengan properti CSS
// dan nilai computed yang diharapkan.
const asersi = [
// .navbar: menempel di atas halaman dengan z-index tinggi.
{ elemen: ".navbar", properti: "position", diharapkan: "sticky" },
{ elemen: ".navbar", properti: "top", diharapkan: "0px" },
{ elemen: ".navbar", properti: "z-index", diharapkan: "100" },
{ elemen: ".navbar", properti: "padding-top", diharapkan: "12px" },
{ elemen: ".navbar", properti: "column-gap", diharapkan: "16px" },
// .nav-menu: flex dengan jarak antar tautan dari token spasi.
{ elemen: ".nav-menu", properti: "display", diharapkan: "flex" },
{ elemen: ".nav-menu", properti: "column-gap", diharapkan: "24px" },
// .card: permukaan putih, border token, radius dari token bentuk.
{ elemen: ".card", properti: "background-color", diharapkan: "rgb(255, 255, 255)" },
{ elemen: ".card", properti: "border-top-color", diharapkan: "rgb(228, 228, 231)" },
{ elemen: ".card", properti: "border-radius", diharapkan: "10px" },
// .card-badan: padding token space-6, jarak baris token space-2.
{ elemen: ".card-badan", properti: "padding-top", diharapkan: "24px" },
{ elemen: ".card-badan", properti: "row-gap", diharapkan: "8px" },
// .card-judul dan .card-teks: tipografi dari token teks.
{ elemen: ".card-judul", properti: "font-size", diharapkan: "20px" },
{ elemen: ".card-judul", properti: "font-weight", diharapkan: "600" },
{ elemen: ".card-teks", properti: "font-size", diharapkan: "14px" },
{ elemen: ".card-teks", properti: "color", diharapkan: "rgb(82, 82, 91)" },
// .tab-aktif: garis bawah 2px primer di atas garis transparan.
{ elemen: ".tab-aktif", properti: "color", diharapkan: "rgb(13, 148, 136)" },
{ elemen: ".tab-aktif", properti: "border-bottom-width", diharapkan: "2px" },
{ elemen: ".tab-aktif", properti: "border-bottom-color", diharapkan: "rgb(13, 148, 136)" },
// .kartu-galeri: bukti perhitungan grid tiga kolom pada wadah 960px.
{ elemen: ".kartu-galeri", properti: "width", diharapkan: "288px" },
];
tests/design-tokens.spec.js
Unduh berkas// ============================================================
// Spesifikasi uji — Proyek: Component Library
// Bagian 1: Design Tokens
// ============================================================
// Berkas ini merangkum asersi yang diverifikasi oleh harness
// pada halaman uji:
// /tests/css/proyek/component-library/design-tokens.html
// Setiap entri memasangkan elemen probe dengan properti CSS
// dan nilai computed yang diharapkan.
const asersi = [
// Token tersimpan di :root (elemen html) dan terbaca apa adanya.
{ elemen: "html", properti: "--color-primary", diharapkan: "#0d9488" },
{ elemen: "html", properti: "--space-6", diharapkan: "24px" },
{ elemen: "html", properti: "--radius-md", diharapkan: "10px" },
{ elemen: "html", properti: "--text-base", diharapkan: "16px" },
// body mengonsumsi token semantik: latar zinc-50, teks zinc-900.
{ elemen: "body", properti: "background-color", diharapkan: "rgb(250, 250, 250)" },
{ elemen: "body", properti: "color", diharapkan: "rgb(24, 24, 27)" },
{ elemen: "body", properti: "font-size", diharapkan: "16px" },
// .wadah: lebar maksimum 960px dengan padding dari token spasi.
{ elemen: ".wadah", properti: "max-width", diharapkan: "960px" },
{ elemen: ".wadah", properti: "padding-top", diharapkan: "24px" },
// .badge: latar primer lunak, teks primer, bentuk pil dari token.
{ elemen: ".badge", properti: "background-color", diharapkan: "rgba(13, 148, 136, 0.1)" },
{ elemen: ".badge", properti: "color", diharapkan: "rgb(13, 148, 136)" },
{ elemen: ".badge", properti: "border-radius", diharapkan: "999px" },
{ elemen: ".badge", properti: "font-size", diharapkan: "14px" },
{ elemen: ".badge", properti: "padding-top", diharapkan: "4px" },
];
tests/themes-dan-documentation.spec.js
Unduh berkas// ============================================================
// Spesifikasi uji — Proyek: Component Library
// Bagian 4: Themes dan Documentation
// ============================================================
// Berkas ini merangkum asersi yang diverifikasi oleh harness
// pada halaman uji:
// /tests/css/proyek/component-library/themes-dan-documentation.html
// Setiap entri memasangkan elemen probe dengan properti CSS
// dan nilai computed yang diharapkan.
const asersi = [
// Tema terang tetap berlaku di luar wadah data-theme.
{ elemen: "body", properti: "background-color", diharapkan: "rgb(250, 250, 250)" },
{ elemen: ".kartu-terang", properti: "background-color", diharapkan: "rgb(255, 255, 255)" },
{ elemen: ".kartu-terang", properti: "border-top-color", diharapkan: "rgb(228, 228, 231)" },
// Wadah gelap: token semantik ditimpa, latar dan garis mengikuti.
{ elemen: ".tema-sampel", properti: "background-color", diharapkan: "rgb(24, 24, 27)" },
{ elemen: ".tema-sampel", properti: "padding-top", diharapkan: "24px" },
{ elemen: ".tema-sampel", properti: "border-top-color", diharapkan: "rgb(63, 63, 70)" },
// Komponen di dalam wadah gelap ikut berganti tanpa aturan baru.
{ elemen: ".kartu-gelap", properti: "background-color", diharapkan: "rgb(39, 39, 42)" },
{ elemen: ".teks-gelap", properti: "color", diharapkan: "rgb(161, 161, 170)" },
// Custom property terwariskan: badge gelap membaca surface baru.
{ elemen: ".badge-gelap", properti: "--color-surface", diharapkan: "#27272a" },
{ elemen: ".badge-gelap", properti: "background-color", diharapkan: "rgba(20, 184, 166, 0.16)" },
// Komponen dokumentasi: swatch token berukuran tetap.
{ elemen: ".swatch", properti: "width", diharapkan: "64px" },
{ elemen: ".swatch", properti: "height", diharapkan: "40px" },
{ elemen: ".swatch", properti: "border-radius", diharapkan: "6px" },
// .contoh-kode memakai primitif zinc: tetap gelap di kedua tema.
{ elemen: ".contoh-kode", properti: "background-color", diharapkan: "rgb(24, 24, 27)" },
{ elemen: ".contoh-kode", properti: "color", diharapkan: "rgb(228, 228, 231)" },
{ elemen: ".contoh-kode", properti: "font-size", diharapkan: "14px" },
{ elemen: ".contoh-kode", properti: "padding-top", diharapkan: "12px" },
{ elemen: ".contoh-kode", properti: "border-radius", diharapkan: "10px" },
];