רכיבי אינטרנט הם רכיבים בהתאמה אישית, Shadow DOM ותבניות HTML: פרימיטיבים של פלטפורמה לרכיבים שניתן לעשות בהם שימוש חוזר, ללא קשר למסגרת, שהתגיות והסגנונות שלהם מופרדים מהמסמך. אפשר להשתמש בהם למערכות עיצוב, לווידג'טים שניתן להטמיע ולממשק משתמש עצמאי.
הכללים הבאים חלים על כל סוגי התוכן. אחזר את המדריך הספציפי למשימה הרלוונטית. כל מדריך מציין מחדש את ההקשר שהוא צריך ומתעד את ממשקי ה-API והמכשולים הייחודיים לו.
החליטו אם אתם בכלל צריכים רכיב מותאם אישית
השתמשו ברכיב מותאם אישית רק כשאתם צריכים התנהגות מובנית, מחזור חיים או API מבוסס-JS שניתן לשימוש חוזר בתג. אל תיצרו מיומנות במקרים הבאים:
- רכיב HTML פשוט עם CSS יספיק. רכיב
<button>או<details>מעוצב נגיש יותר וזול יותר מהטמעה מחדש. - הדבר הוא רק תצוגה ללא התנהגות. מחלקה ברכיב מקורי היא יעילה יותר, וניתן להגדיר לה היקף באמצעות
@layerאו@scope. - אתם צריכים רק היקף סגנון בשרת ללא אינטראקטיביות. יכול להיות שגיליון סגנונות בהיקף או Declarative Shadow DOM (ללא שדרוג) יספיקו.
השימוש השגוי הנפוץ ביותר הוא בנייה מחדש של סמנטיקה מקומית (<my-button> בהתאמה אישית שיוצר מחדש את המיקוד, ההפעלה ו-ARIA): אתם מקבלים את הנגישות של הפלטפורמה בחינם רק אם אתם משתמשים שוב ברכיב המקומי. כשיש הצדקה ל-wrapper בסגנון <my-button> – בדרך כלל בשביל הוקים משותפים של עיצוב, תגי עיצוב נוספים או התנהגות שרכיב מקורי לא יכול לבטא – צריך לעטוף את ה-<button> האמיתי במקום להטמיע אותו מחדש (אפשר לעיין במאמר עיצוב רכיבי אינטרנט כדי להעביר סגנונות לרכיב מקורי פנימי).
הבדיקה היא אם אתם צריכים מצב מובנה, API שניתן להריץ בו סקריפטים או התנהגות שהרכיב המקורי לא יכול לבטא – ולא רק מראה שונה. מתג לייק/מועדפים מתאים: הוא נושא מצב דומיין נעול, חושף את המצב הזה כ-styling hook לדף שמסביב, ושולח אירוע change משלו – אף אחד מהם לא מסופק על ידי <button> מעוצב. לחצן שרק משנה את הצבע שלו כשלוחצים עליו לא עושה את זה: צריך להשתמש ב-<button> וב-CSS. כשיוצרים אותו, צריך ליצור מודל של המצב שלו באמצעות מצב או מאפיין בהתאמה אישית, לפי הצורך (ראו רכיבים בהתאמה אישית).
התאמת הכלי לבסיס הקוד
ההחלטה אם כדאי להשתמש ברכיב מותאם אישית תלויה ברכיבים שכבר נמצאים בשימוש בפרויקט. סוכנים נוטים להפשטת יתר ולשימוש ברכיב חדש מהר מדי – אם יש ספק, האפשרות הקלה יותר (רכיב מקורי, CSS, תבנית שרת) היא בדרך כלל הנכונה, ואפשר לקדם לרכיב מותאם אישית מאוחר יותר אם השימוש החוזר או ההתנהגות באמת דורשים זאת. היוריסטיקה, לפי סדר עדיפות כללי:
- בבסיס הקוד כבר יש מודל רכיבים (React, Vue, Svelte וכו'). כברירת מחדל, צריך להשתמש ברכיב של המסגרת הזו לממשק המשתמש בתוך האפליקציה. השתמשו ברכיב מותאם אישית רק כשהרכיב צריך לחרוג מהמסגרת או להמשיך לפעול אחריה: פרימיטיב של מערכת עיצוב שמשותף בין אפליקציות או מסגרות, ווידג'ט שמוכנס לתגי עיצוב שהמסגרת לא שולטת בהם, או פלט שצריך לפעול כ-HTML פשוט (אימייל, CMS, קטעי SSR). אל תגדירו מערכת רכיבים מקבילה לתצוגות מפורטות של אפליקציה רגילות בתוך האפליקציה.
- אין כלים, בעיקר תגי עיצוב סטטיים. עדיף להשתמש ב-HTML ו-CSS פשוטים, או בתבנית/חלק של שרת. רכיב מותאם אישית מצדיק את קיומו רק כשבאמת צריך התנהגות, מחזור חיים או API שמגובה ב-JS בתג – ולא רק כדי לשתף תגי עיצוב, שניתן לעשות באמצעות הכללה בצד השרת או
<template>בלי לשלוח JS. - מחולל אתרים סטטיים עם איים של אינטראקטיביות. מבצעים רינדור סטטי של תגי העיצוב, ושומרים את הרכיב המותאם אישית לחלק האינטראקטיבי. אם יש לכם "הרבה תגי עיצוב וקצת אינטראקטיביות", כדאי לשמור את תגי העיצוב ב-Light DOM (או ב-Declarative Shadow DOM) ולאפשר לרכיב קטן בהתאמה אישית לשפר אותו בשיפור הדרגתי (progressive enhancement), במקום לעבד מחדש את הכול מ-JS.
- במקום זאת, אפשר להרחיב את השימוש ברכיב מובנה. בדרך כלל עדיף להשתמש ברכיב מקורי ככל האפשר (CSS, כמה מאזינים, רכיב פסאודו מדי פעם) על פני רכיב מותאם אישית, כי אתם שומרים על הנגישות וההתנהגות של הפלטפורמה בחינם. עברו לרכיב מותאם אישית כשהפתרונות החלופיים מפסיקים להיות ניתנים לתחזוקה – כשתצטרכו להילחם בהתנהגות המובנית של הרכיב, או כשחוויית היצירה תהיה גרועה יותר מ-API של רכיב נקי. הצורך להוסיף קצת JS לרכיב מובנה הוא לא סיבה להחליף אותו.
כללים רוחביים
ההנחיות האלה רלוונטיות לכל המדריכים שבהמשך:
- חובה: שם התג חייב להיות בפורמט kebab case עם מקף אחד לפחות (למשל
my-element). זה מה שמבדיל בין רכיבים מותאמים אישית לבין רכיבים מובנים קיימים ועתידיים. - חובה: צריך לקרוא ל-
super()קודם ב-constructor, לפני שנוגעים ב-this. קריאה ל- אחרי הצהרה כלשהי שקוראת או כותבתthisגורמת לזריקת חריגה. - חובה: צריך להשתמש ברכיבים סמנטיים (
<button>,<nav>,<ul>) בתוך תבניות צל. רוב הכשלים בנגישות בעצי צל נובעים מתגי עיצוב לא סמנטיים. משבצת לא משנה את התפקיד של מה שהיא מקרינה. - חובה: הפניות ARIA
id (aria-labelledby,aria-describedby,aria-controls) לא יכולות לחצות גבול של Shadow DOM. הרכיב שמפנה וה-idשאליו הוא מפנה חייבים להיות באותו עץ. - עדיף להשתמש ב-
attachShadow({ mode: 'open' })כדי שכלי הפיתוח, הסקריפטים של הדף וההידרציה של השרת יוכלו להגיע אלelement.shadowRoot. השתמשו ב-'closed'רק כשאתם חייבים להסתיר את המבנה הפנימי מסקריפטים של דפים. - הימנעו מרכיבים מובְנים בהתאמה אישית (
extends HTMLButtonElementעםis="…"). ב-Safari סירבו באופן סופי להוסיף אותם.
מטריצת מדריכים לתרחישי שימוש
מזהים את המשימה ומאחזרים את המדריך שלה:
| אם אתם צריכים… | אחזור |
|---|---|
| הגדרת תג סמנטי חדש עם התנהגות ומחזור חיים | רכיבים מותאמים אישית |
| הגדרת הסגנונות ותגי העיצוב של רכיב, והצגת תוכן של צרכן בתוכו | Shadow DOM, Templates & Slots |
| עיבוד של עץ הצללים של רכיב בשרת (SSR) בלי הבזק של תוכן לא מעוצב | עיבוד מראש של רכיבים בהתאמה אישית |
עיצוב מעבר לגבולות הצל (עיצוב, ::part, מאפיינים מותאמים אישית) |
עיצוב רכיבי אינטרנט |
שליחת ערך של פקד מותאם אישית אל <form> שמקיף אותו |
רכיבים מותאמים אישית שמשויכים לטופס |
| הנגשת רכיב בהתאמה אישית (תפקידים, מיקוד, ARIA בשורשי צל) | רכיבי אינטרנט נגישים |