Cara Nordhealth menggunakan Properti Khusus di Komponen Web

Manfaat menggunakan Properti Khusus dalam sistem desain dan library komponen.

David Darnes
David Darnes

Saya Dave, Senior Front-end Developer di Nordhealth. Saya mengerjakan desain dan pengembangan Nod sistem desain kami, yang mencakup pembuatan Komponen Web untuk library komponen kami. Saya ingin berbagi cara kami menyelesaikan masalah seputar penataan gaya Komponen Web dengan menggunakan Properti Khusus CSS, dan beberapa manfaat lain menggunakan Properti Khusus dalam sistem desain dan library komponen.

Bagaimana kami membangun Komponen Web

Untuk membuat Komponen Web, kami menggunakan Lit, library yang menyediakan banyak kode boilerplate seperti status, gaya cakupan, pemberian template, dan lainnya. Lit tidak hanya ringan, tetapi juga dibuat di JavaScript API native, yang berarti kami dapat mengirimkan paket kode ramping yang memanfaatkan fitur yang sudah dimiliki browser.


import {html, css, LitElement} from 'lit';

export class SimpleGreeting extends LitElement {
  static styles = css`:host { color: blue; font-family: sans-serif; }`;

  static properties = {
    name: {type: String},
  };

  constructor() {
    super();
    this.name = 'there';
  }

  render() {
    return html`

Hey ${this.name}, welcome to Web Components!

`; } } customElements.define('simple-greeting', SimpleGreeting);
Komponen Web yang ditulis dengan Lit.

Namun, hal yang paling menarik tentang Komponen Web adalah komponen ini dapat berfungsi dengan hampir semua framework JavaScript yang ada, atau bahkan tidak menggunakan framework sama sekali. Setelah paket JavaScript utama direferensikan di laman, menggunakan Komponen Web sangat mirip dengan menggunakan elemen HTML bawaan. Satu-satunya tanda yang nyata bahwa ini bukan elemen HTML native adalah tanda hubung yang konsisten dalam tag, yang merupakan standar untuk menunjukkan kepada browser bahwa ini adalah Komponen Web.


// TODO: DevSite - Code sample removed as it used inline event handlers
Menggunakan Komponen Web yang dibuat di atas pada halaman.

Enkapsulasi gaya Shadow DOM

Mirip dengan elemen HTML native yang memiliki Shadow DOM, begitu juga dengan Komponen Web. Shadow DOM adalah pohon simpul tersembunyi dalam sebuah elemen. Cara terbaik untuk memvisualisasikannya adalah dengan membuka web inspector dan mengaktifkan opsi "Show Shadow DOM tree". Setelah selesai, coba lihat elemen input native dalam pemeriksa—Anda sekarang memiliki opsi untuk membuka input tersebut dan melihat semua elemen di dalamnya. Anda bahkan dapat mencobanya dengan salah satu Komponen Web kami—coba periksa komponen input kustom kami untuk melihat Shadow DOM-nya.

Shadow DOM yang diperiksa di DevTools.
Contoh Shadow DOM dalam elemen input teks biasa dan di Komponen Web input Nord.

Salah satu kelebihan (atau kekurangannya, bergantung pada pandangan Anda) dari Shadow DOM adalah enkapsulasi gaya. Jika Anda menulis CSS di dalam Komponen Web Anda, gaya tersebut tidak akan bocor dan memengaruhi laman utama atau elemen lainnya; gaya tersebut sepenuhnya terkandung dalam komponen. Selain itu, CSS yang ditulis untuk laman utama atau Komponen Web induk tidak dapat bocor ke Komponen Web Anda.

Enkapsulasi gaya ini merupakan manfaat dalam library komponen kita. Ini memberi kami lebih banyak jaminan bahwa saat seseorang menggunakan salah satu komponen kami, komponen tersebut akan terlihat seperti yang kami inginkan, terlepas dari gaya yang diterapkan pada halaman induk. Dan untuk lebih memastikan, kita menambahkan all: unset; ke root, atau "host", dari semua Komponen Web.


:host {
  all: unset;
  display: block;
  box-sizing: border-box;
  text-align: start;
  /* ... */
}
Beberapa kode boilerplate komponen diterapkan ke shadow root atau pemilih host.

Namun, bagaimana jika seseorang yang menggunakan Komponen Web Anda memiliki alasan yang sah untuk mengubah gaya tertentu? Mungkin ada baris teks yang perlu lebih kontras karena konteksnya, atau batasnya harus lebih tebal? Jika tidak ada gaya yang bisa masuk ke komponen Anda, bagaimana Anda bisa membuka opsi gaya tersebut?

Di sinilah Properti Khusus CSS berperan.

Properti Khusus CSS

Properti Khusus diberi nama dengan sangat tepat—properti tersebut adalah properti CSS yang dapat Anda beri nama sepenuhnya dan terapkan nilai apa pun yang diperlukan. Satu-satunya persyaratan adalah Anda mengawalinya dengan dua tanda hubung. Setelah Anda mendeklarasikan properti khusus, nilai tersebut dapat digunakan di CSS menggunakan fungsi var().


:root {
  --n-color-accent: rgb(53, 89, 199);
  /* ... */
}

.n-color-accent-text {
  color: var(--n-color-accent);
}
Contoh token desain dari Framework CSS kami sebagai Properti Khusus dan yang digunakan di class helper.

Dalam hal pewarisan, semua Properti Khusus diwarisi, yang mengikuti perilaku umum properti dan nilai CSS reguler. Setiap properti khusus yang diterapkan pada elemen induk, atau elemen itu sendiri, dapat digunakan sebagai nilai di properti lain. Kami banyak menggunakan Properti Khusus untuk token desain dengan menerapkannya ke elemen root melalui Kerangka Kerja CSS kami, yang berarti bahwa semua elemen pada laman dapat menggunakan nilai token ini, baik itu Komponen Web, kelas bantuan CSS, atau pengembang yang ingin mengambil nilai dari daftar token kami.

Kemampuan untuk mewarisi Properti Kustom ini, dengan penggunaan fungsi var(), adalah cara kita menembus Shadow DOM Komponen Web dan memungkinkan developer memiliki kontrol yang lebih mendetail saat menata gaya komponen.

Properti Khusus di Komponen Web Nord

Setiap kali mengembangkan komponen untuk sistem desain, kami mengambil pendekatan yang bijaksana pada CSS-nya—kami ingin kode yang ramping tetapi sangat mudah dikelola. Token desain yang kita miliki didefinisikan sebagai Properti Khusus dalam Framework CSS utama pada elemen root.


:root {
  --n-space-m: 16px;
  --n-space-l: 24px;
  /* ... */
  --n-color-background: rgb(255, 255, 255);
  --n-color-border: rgb(216, 222, 228);
  /* ... */
}
Properti Kustom CSS sedang ditentukan di pemilih root.

Nilai token ini kemudian direferensikan dalam komponen kita. Dalam beberapa kasus, kita akan menerapkan nilai secara langsung di properti CSS, tetapi untuk kasus yang lain, kita sebenarnya akan menentukan Properti Khusus kontekstual baru dan menerapkan nilai ke properti tersebut.


:host {
  --n-tab-group-padding: 0;
  --n-tab-list-background: var(--n-color-background);
  --n-tab-list-border: inset 0 -1px 0 0 var(--n-color-border);
  /* ... */
}

.n-tab-group-list {
  box-shadow: var(--n-tab-list-border);
  background-color: var(--n-tab-list-background);
  gap: var(--n-space-s);
  /* ... */
}
Properti Khusus ditentukan pada root bayangan komponen, lalu digunakan dalam gaya komponen. Properti Kustom dari daftar token desain juga digunakan.

Kita juga akan memisahkan beberapa nilai yang spesifik untuk komponen, tetapi tidak pada token, dan mengubahnya menjadi Properti Kustom kontekstual. Properti Kustom yang kontekstual dengan komponen memberi kami dua manfaat utama. Pertama, ini berarti kita bisa lebih "keras" dengan CSS karena nilai tersebut dapat diterapkan ke beberapa properti di dalam komponen.


.n-tab-group-list::before {
  /* ... */
  padding-inline-start: var(--n-tab-group-padding);
}

.n-tab-group-list::after {
  /* ... */
  padding-inline-end: var(--n-tab-group-padding);
}
Properti Kustom kontekstual padding grup tab digunakan di beberapa tempat dalam kode komponen.

Kedua, membuat perubahan status komponen dan variasi benar-benar bersih—hanya properti khusus yang perlu diubah untuk memperbarui semua properti tersebut ketika, misalnya, Anda menata gaya mengambang atau status aktif atau, dalam hal ini, variasi.


:host([padding="l"]) {
  --n-tab-group-padding: var(--n-space-l);
}
Variasi komponen tab tempat padding diubah menggunakan satu update Properti Kustom, bukan beberapa update.

Namun, manfaat yang paling kuat adalah saat menentukan Properti Kustom kontekstual ini pada suatu komponen, kita membuat semacam CSS API kustom untuk setiap komponen, yang dapat dimanfaatkan oleh pengguna komponen tersebut.


<nord-tab-group label="Title">
  <!-- ... -->
</nord-tab-group>

<style>
  nord-tab-group {
    --n-tab-group-padding: var(--n-space-xl);
  }
</style>
Menggunakan komponen grup tab di halaman dan memperbarui Properti Khusus padding ke ukuran yang lebih besar.

Contoh sebelumnya menunjukkan salah satu Komponen Web kami dengan Properti Khusus kontekstual yang diubah melalui pemilih. Hasil dari seluruh pendekatan ini adalah komponen yang memberikan fleksibilitas gaya yang cukup kepada pengguna sambil tetap memeriksa sebagian besar gaya sebenarnya. Selain itu, sebagai bonus, kita sebagai developer komponen memiliki kemampuan untuk menangkap gaya yang diterapkan oleh pengguna. Jika ingin menyesuaikan atau memperluas salah satu properti tersebut, kita dapat melakukannya tanpa pengguna perlu mengubah kodenya.

Kami merasa pendekatan ini sangat ampuh, tidak hanya bagi kami sebagai kreator komponen sistem desain, tetapi juga untuk tim pengembangan saat mereka menggunakan komponen tersebut dalam produk kami.

Mengembangkan Properti Khusus

Pada saat penulisan ini, kami tidak mengungkapkan Properti Khusus kontekstual ini dalam dokumentasi kami; namun, kami berencana melakukannya agar tim pengembangan kami yang lebih luas dapat memahami dan memanfaatkan properti ini. Komponen kami dikemas di npm dengan file manifes, yang berisi semua yang perlu diketahui tentangnya. Kemudian, kami menggunakan file manifes sebagai data saat situs dokumentasi di-deploy, yang dilakukan menggunakan Eleventy dan fitur Data Global. Kami berencana untuk menyertakan Properti Khusus kontekstual ini dalam file data manifes ini.

Area lain yang ingin kami tingkatkan adalah cara Properti Khusus kontekstual ini mewarisi nilai. Saat ini, misalnya, jika ingin menyesuaikan warna dua komponen pembagi, Anda harus menargetkan kedua komponen tersebut secara khusus dengan pemilih, atau menerapkan properti khusus secara langsung pada elemen dengan atribut gaya. Hal ini mungkin tampak baik-baik saja, tetapi akan lebih membantu jika developer dapat menentukan gaya tersebut pada elemen penampung atau bahkan di tingkat root.


<nord-divider></nord-divider>

<section>
  <nord-divider></nord-divider>
   <!-- ... -->
</section>

<style>
  nord-divider {
    --n-divider-color: var(--n-color-status-danger);
  }

  section {
    padding: var(--n-space-s);
    background: var(--n-color-surface-raised);
  }
  
  section nord-divider {
    --n-divider-color: var(--n-color-status-success);
  }
</style>
Dua instance komponen pembagi yang memerlukan dua perlakuan warna berbeda. Satu elemen ditempatkan di dalam bagian yang dapat kita gunakan untuk pemilih yang lebih spesifik, tetapi kita harus menargetkan pemisah secara spesifik.

Alasan Anda harus menetapkan nilai Properti Khusus secara langsung pada komponen adalah karena kita menentukannya pada elemen yang sama melalui pemilih host komponen. Token desain global yang kita gunakan secara langsung dalam komponen akan langsung lolos, tidak terpengaruh oleh masalah ini, dan bahkan dapat dicegat pada elemen induk. Bagaimana kita bisa mendapatkan yang terbaik dari keduanya?

Properti Khusus Pribadi dan publik

Properti kustom pribadi adalah properti yang telah disusun oleh Lea Verou, yang merupakan Properti Kustom "pribadi" kontekstual pada komponen itu sendiri, tetapi ditetapkan ke Properti Kustom "publik" dengan penggantian.



:host {
  --_n-divider-color: var(--n-divider-color, var(--n-color-border));
  --_n-divider-size: var(--n-divider-size, 1px);
}

.n-divider {
  border-block-start: solid var(--_n-divider-size) var(--_n-divider-color);
  /* ... */
}
CSS Komponen Web pembagi dengan Properti Khusus kontekstual yang disesuaikan sehingga CSS internal bergantung pada Properti Khusus pribadi, yang telah ditetapkan ke Properti Khusus publik dengan penggantian.

Dengan menentukan Properti Khusus kontekstual dengan cara ini, berarti kita masih bisa melakukan semua hal yang kita lakukan sebelumnya, seperti mewarisi nilai token global dan menggunakan kembali nilai di seluruh kode komponen; tetapi komponen juga akan dengan baik mewarisi definisi baru dari properti tersebut di elemen itu sendiri atau elemen induk.


<nord-divider></nord-divider>

<section>
  <nord-divider></nord-divider>
   <!-- ... -->
</section>

<style>
  nord-divider {
    --n-divider-color: var(--n-color-status-danger);
  }

  section {
    padding: var(--n-space-s);
    background: var(--n-color-surface-raised);
    --n-divider-color: var(--n-color-status-success);
  }
</style>
Kedua pemisah itu lagi, tetapi kali ini pemisah tersebut dapat diubah warnanya dengan menambahkan Properti Kustom kontekstual pembagi ke pemilih bagian. Pembagi akan mewarisinya, sehingga menghasilkan potongan kode yang lebih rapi dan lebih fleksibel.

Meskipun ada pendapat bahwa metode ini tidak benar-benar "pribadi", kami tetap berpikir ini adalah solusi yang cukup elegan untuk masalah yang kami khawatirkan. Jika ada kesempatan, kami akan mengatasinya dalam komponen kami sehingga tim pengembangan kami memiliki kontrol lebih atas penggunaan komponen sambil tetap mendapatkan manfaat dari pagar pembatas yang kami miliki.

Saya harap Anda mendapatkan manfaat dari wawasan tentang cara kami menggunakan Komponen Web dengan Properti Khusus CSS. Beri tahu kami pendapat Anda. Jika Anda memutuskan untuk menggunakan salah satu metode ini dalam pekerjaan Anda sendiri, Anda dapat menghubungi saya di Twitter @DavidDarnes. Anda juga dapat menemukan Nordhealth @NordhealthHQ di Twitter, serta tim lainnya yang telah bekerja keras untuk menyatukan sistem desain ini dan menjalankan fitur yang disebutkan dalam artikel ini: @Viljamis, @WickyNilliams, dan @eric_habich.

Banner besar oleh Dan Cristian Păduretel