2024. 9. 2. 23:48ㆍit/프론트엔드
Web Components : Custom Elements
html 에서도 react 나 vue 처럼 컴포넌트 단위로 작업을 할 수 있는지 궁금하여 검색해보다가 Custom Elements 에 대해서 알게 되었다.
문서에는 Custom Elements에 대해 아래와 같이 설명이 되어 있다.
웹 컴포넌트 표준의 주요 기능 중 하나는 사용자 정의 페이지 기능을 제공하는 길고 중첩된 요소들의 묶음으로 만족하는 것보다는, HTML 페이지에서 기능을 캡슐화하는 사용자 정의 요소를 생성하는 능력입니다.
Custom Elements 작성
크게 두 파트로 나뉜다. 1. 커스텀 요소를 구현. 하고 2. 커스텀 요소를 정의(등록) 한다.
1. 구현
class 클래스이름 extends HTMLParagraphElement
<script>
class WordCount extends HTMLParagraphElement {
constructor() {
// 항상 super를 생성자에서 먼저 호출합니다
super();
// 요소 기능은 여기 작성됩니다
...
}
}
</script>
2. 정의(등록)
.define()
<script>
/*
첫번째 매개변수 : 요소의 이름
두번째 매개변수 : 요소의 기능을 정의한 클래스 이름
세번째 매개변수 : 옵션(예: 실제로 확장할 HTML 태그 이름 등)
*/
customElements.define("word-count", WordCount, { extends: "p" });
</script>
3. 사용
<body>
<word-count></word-count>
</body>
Custom Elements 간단한 사용 예시
class MyButton extends HTMLElement {
constructor() {
super();
this.style.border = '1px solid';
this.addEventListender('click', (e) => e.preventDefault());
}
}
customElements.define("my-button", MyButton);
<my-button>Click</my-button>
결과 : 1px solid border 스타일을 가지고, click 이벤트를 가지고 있는 my-button 이라는 HTML 태그
Shadow DOM
웹 컴포넌트 API가 추가되면서, Custom Elements와 함께 Shadow DOM도 추가되었다고 한다.
문서에서는 Shadow DOM에 대해 아래 처럼 설명하고 있다.
웹 컴포넌트의 중요한 측면은 캡슐화입니다. 캡슐화를 통해 마크업 구조, 스타일, 동작을 숨기고 페이지의 다른 코드로부터의 분리하여 각기 다른 부분들이 충돌하지 않게 하고, 코드가 깔끔하게 유지될 수 있게 합니다. Shadow DOM API는 캡슐화의 핵심 파트이며, 숨겨진 분리된 DOM을 요소에 부착하는 방법을 제공합니다.
즉, Shadow DOM을 사용하면 마크업과 스타일, 동작을 전부 캡슐화할 수 있다.
Shadow DOM 작성 및 사용 예시
Shadow DOM을 사용하려면, Shadow DOM으로 사용하려는 일반적인 Element에 Shadow를 부착한다고 생각하면 쉽다.
Shadow를 부착하면 해당 요소는 Shadow root가 된다.
this.attachShadow({ mode: "open" }); 이 코드 하나로 Shadow root가 생성된다.
<script>
class PopupInfo extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
}
connectedCallback() {
// 해당 PopupInfo CustomElement에 shadow root 생성
const shadow = this.attachShadow({ mode: "open" });
// 옵션 mode가 open이면 javascript의 Element.shadowRoot를 사용하여 외부에서 접근이 가능하다.
// 예시 : let myShadowDom = myCustomElem.shadowRoot;
// 옵션 mode가 close이면 접근 불가능.
// 다양한 요소 및 속성 추가
// ...생략...
// 외부 stylesheet도 추가 가능하다.
const linkElem = document.createElement("link");
linkElem.setAttribute("rel", "stylesheet");
linkElem.setAttribute("href", "style.css");
// shadow dom에 여러 Elements와 스타일을 부착할 수 있다.
shadow.appendChild(linkElem);
shadow.appendChild(wrapper);
wrapper.appendChild(icon);
wrapper.appendChild(info);
}
}
// 위에서 본 Custom Element정의하기 처럼 define() 으로 정의.
customElements.define("popup-info", PopupInfo);
</script>
위 처럼 작성하면 해당하는 요소는 shadow Element (shadow root)가 되고, 해당 root로부터 추가되는 모든 자식 요소들도 shadow가 된다.
마지막
태그 이름을 커스텀하여 사용하기 때문에 혹시나 싶어 웹 표준이나 웹 접근성에 문제가 있지 않을까 생각되어서 검색해 보니, Custom Elements 는 당연하게도 웹 표준의 일부이므로 웹 표준에는 문제가 없다고 한다.
한편, 웹 접근성 측면에서는 몇가지 고려 사항이 있는데,
- 명명 규칙으로 태그 이름에 반드시 하이픈(-)을 반드시 포함해야 한다고 한다.
예를 들어 <my-element> 는 유효하지만, <myelement> 는 유효하지 않다.
이 규칙은 기존 HTML 태그와 Custom Element를 구분하기 위해 존재한다고 한다. - ARIA 속성을 사용하여 요소의 역할과 상태를 명확히하면 좋다.
class MyButton extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
const button = document.createElement('button');
button.setAttribute('role', 'button'); // ARIA 속성 설정
button.textContent = 'Click Me';
shadow.appendChild(button);
}
}
customElements.define('my-button', MyButton);
- 기본 요소를 확장하여 사용하기.
예를 들어 <button> 요소를 확장한 커스텀 버튼을 만들면, 기본 접근성 기능을 그대로 유지하면서 추가적인 기능을 제공할 수 있다.
customElements.define() 함수의 3번째 매개변수로 확장할 HTML 태그 이름을 넣어주면 된다.
class MyButton extends HTMLButtonElement {
constructor() {
super();
this.textContent = 'Custom Button';
}
}
customElements.define('my-button', MyButton, { extends: 'button' });
<button is="my-button"></button>
참고
https://developer.mozilla.org/ko/docs/Web/API/Web_components/Using_custom_elements
https://developer.mozilla.org/ko/docs/Web/API/Web_components/Using_shadow_DOM
https://solo5star.tistory.com/25
https://github.com/mdn/web-components-examples/blob/main/popup-info-box-external-stylesheet/main.js
'it > 프론트엔드' 카테고리의 다른 글
기본 유효성 체크의 사용자 정의 유효성 (1) | 2024.08.18 |
---|---|
javascript로 요소에 적용된 css 스타일 가져오기 (1) | 2024.04.14 |
오픈 그래프(Open Graph) 태그 (0) | 2023.11.28 |