[Part 2] Web Components — Custom Elements 완전 정복
customElements.define()으로 나만의 HTML 태그를 만드는 방법. Autonomous vs Customized built-in elements 차이와 실전 예제를 다룹니다.
[Part 2] Web Components — Custom Elements 완전 정복
Part 1에서는 Web Components가 무엇인지, 왜 등장했는지, 그리고 어떤 핵심 기술들로 구성되어 있는지 알아봤다.
이번 글에서는 Web Components의 가장 기본이 되는 Custom Elements를 자세히 살펴본다.
Custom Elements를 이해하면 Web Components의 절반은 이해했다고 볼 수 있다. 왜냐하면 Web Components의 출발점이 바로 직접 HTML 태그를 만드는 것이기 때문이다.
1. Custom Elements란?
AD
제휴 광고 · 일부 링크는 수수료를 받을 수 있습니다
Custom Elements는 개발자가 직접 HTML 태그를 정의할 수 있게 해주는 브라우저 표준 기술이다.
HTML에는 기본적으로 브라우저가 미리 정해둔 태그들이 있다.
<div></div>
<button></button>
<input />
<section></section>
<article></article>
이런 태그들은 브라우저가 기본적으로 알고 있다.
하지만 Custom Elements를 사용하면 개발자가 직접 새로운 태그를 만들 수 있다.
<my-button></my-button>
<user-card></user-card>
<product-item></product-item>
여기서 <my-button>, <user-card>, <product-item>은 HTML 기본 태그가 아니다.
개발자가 직접 정의한 커스텀 태그다.
정리하면 Custom Elements는 브라우저에게 새로운 HTML 태그를 알려주는 기술이다.
2. 왜 직접 태그를 만들까?
웹 페이지를 만들다 보면 같은 UI를 여러 번 사용하게 된다.
- 버튼
- 카드
- 상품 박스
- 프로필 영역
- 알림 메시지
- 모달
예를 들어 사용자 카드 UI를 만든다고 해보자.
<article>
<h3>사용자 이름</h3>
<p>사용자 설명</p>
</article>
이 구조를 여러 곳에서 반복해서 사용한다면 매번 같은 HTML을 작성해야 한다.
Custom Elements를 사용하면 이 구조를 하나의 태그로 만들 수 있다.
<user-card></user-card>
이렇게 하면 HTML을 읽는 사람도 이 요소가 사용자 카드라는 것을 쉽게 알 수 있다.
즉 Custom Elements는 단순히 코드를 줄이는 목적만 있는 것이 아니라, HTML 구조를 더 의미 있게 만들기 위해서도 사용된다.
3. 커스텀 태그 이름 규칙
Custom Elements를 만들 때 가장 먼저 알아야 할 규칙이 있다.
커스텀 태그 이름에는 반드시 하이픈(-)이 들어가야 한다.
가능한 이름은 다음과 같다.
<my-button></my-button>
<user-card></user-card>
<product-item></product-item>
<app-modal></app-modal>
반대로 다음 이름은 사용할 수 없다.
<mybutton></mybutton>
<usercard></usercard>
<card></card>
<modal></modal>
하이픈이 필요한 이유는 브라우저 기본 태그와 구분하기 위해서다.
예를 들어 미래에 HTML 표준에 <card>라는 태그가 추가될 수도 있다. 그러면 개발자가 만든 <card>와 브라우저 기본 <card>가 충돌할 수 있다.
그래서 브라우저는 커스텀 태그 이름에 하이픈을 강제한다.
4. HTMLElement란?
Custom Element를 만들 때는 JavaScript class를 사용한다.
그리고 그 class는 보통 HTMLElement를 상속받는다.
class MyButton extends HTMLElement {
}
HTMLElement는 브라우저가 제공하는 기본 HTML 요소 클래스다.
쉽게 말하면 <div>, <button>, <section> 같은 HTML 요소들이 공통으로 가지는 기본 기능을 담고 있는 부모 개념이다.
JavaScript에서 HTML 요소를 선택하면 객체처럼 다룰 수 있다.
const button = document.querySelector('button');
console.log(button instanceof HTMLElement);
button instanceof HTMLElement는 선택한 button 요소가 HTMLElement를 기반으로 만들어졌는지 확인하는 코드다.
Custom Element도 결국 HTML 요소처럼 동작해야 하므로 HTMLElement를 상속받는다.
5. extends란?
extends는 JavaScript class에서 다른 class의 기능을 물려받을 때 사용한다.
class Animal {
move() {
console.log('움직입니다.');
}
}
class Dog extends Animal {
bark() {
console.log('멍멍');
}
}
const dog = new Dog();
dog.move();
dog.bark();
Dog extends Animal은 Dog가 Animal의 기능을 물려받는다는 뜻이다.
그래서 Dog에는 직접 만든 bark()뿐만 아니라 Animal에서 물려받은 move()도 있다.
Custom Element에서는 다음처럼 사용한다.
class MyButton extends HTMLElement {
}
이 코드는 MyButton이 HTML 요소로 동작하기 위해 HTMLElement의 기본 기능을 물려받는다는 뜻이다.
6. customElements.define()
class만 만든다고 커스텀 태그가 바로 동작하지는 않는다.
브라우저에게 “이 태그 이름은 이 class와 연결된다”라고 등록해야 한다.
이때 사용하는 API가 customElements.define()이다.
customElements.define('my-button', MyButton);
첫 번째 값은 사용할 태그 이름이다.
두 번째 값은 해당 태그와 연결할 class다.
즉 위 코드는 브라우저에게 이렇게 알려주는 것이다.
my-button 태그를 만나면 MyButton 클래스를 사용해라.
7. connectedCallback()
AD
제휴 광고 · 일부 링크는 수수료를 받을 수 있습니다
파블로 - 키울수록 돈버는 리워드 앱테크
Web3.0 학습과 리워드가 결합된 앱테크 플랫폼!
connectedCallback()은 Custom Element의 생명주기 메서드 중 하나다.
생명주기 메서드는 특정 시점에 브라우저가 자동으로 실행해주는 메서드다.
connectedCallback()은 커스텀 요소가 HTML 문서에 추가될 때 실행된다.
class MyButton extends HTMLElement {
connectedCallback() {
console.log('화면에 추가됨');
}
}
customElements.define('my-button', MyButton);
HTML에 다음 태그가 있으면
<my-button></my-button>
브라우저가 이 요소를 문서에 추가하면서 connectedCallback()을 실행한다.
보통 connectedCallback() 안에서 화면에 표시할 HTML을 만든다.
8. 첫 번째 Custom Element 만들기
이제 직접 간단한 버튼 컴포넌트를 만들어보자.
class MyButton extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<button>확인</button>
`;
}
}
customElements.define('my-button', MyButton);
HTML에서는 이렇게 사용한다.
<my-button></my-button>
브라우저는 <my-button>을 보고 MyButton 클래스를 실행한다.
그리고 connectedCallback() 안에서 this.innerHTML을 통해 내부에 실제 button 요소를 넣는다.
코드 리뷰
class MyButton extends HTMLElement는 MyButton이라는 커스텀 요소 클래스를 만든다.
connectedCallback()은 요소가 화면에 추가될 때 실행된다.
this는 현재 커스텀 요소인 <my-button>을 의미한다.
this.innerHTML은 현재 요소 내부에 HTML을 삽입한다.
customElements.define('my-button', MyButton)은 <my-button> 태그와 MyButton 클래스를 연결한다.
9. Attribute로 값 전달하기
커스텀 태그도 일반 HTML 태그처럼 attribute를 받을 수 있다.
<user-card name="사용자" role="관리자"></user-card>
여기서 name과 role은 attribute다.
JavaScript에서는 getAttribute()로 값을 가져올 수 있다.
class UserCard extends HTMLElement {
connectedCallback() {
const name = this.getAttribute('name');
const role = this.getAttribute('role');
this.innerHTML = `
<article>
<h3>${name}</h3>
<p>${role}</p>
</article>
`;
}
}
customElements.define('user-card', UserCard);
이제 HTML에서 다음처럼 사용할 수 있다.
<user-card name="사용자" role="관리자"></user-card>
화면에는 사용자 이름과 역할이 출력된다.
코드 리뷰
this.getAttribute('name')은 현재 요소의 name attribute 값을 가져온다.
this.getAttribute('role')은 role attribute 값을 가져온다.
${name}과 ${role}은 가져온 값을 HTML 문자열 안에 넣는 문법이다.
10. 같은 컴포넌트 여러 번 사용하기
Custom Element는 한 번 정의하면 여러 번 사용할 수 있다.
<user-card name="사용자 A" role="관리자"></user-card>
<user-card name="사용자 B" role="일반 회원"></user-card>
<user-card name="사용자 C" role="게스트"></user-card>
각 <user-card>는 자기 attribute 값을 읽어서 다른 내용을 출력한다.
이것이 컴포넌트 재사용의 핵심이다.
11. 중복 등록 주의
같은 이름의 Custom Element는 한 번만 등록할 수 있다.
customElements.define('my-button', MyButton);
customElements.define('my-button', MyButton);
이렇게 같은 이름으로 두 번 등록하면 에러가 발생한다.
개발 중에 파일이 여러 번 로드되거나, 같은 코드가 중복 실행되면 이런 문제가 생길 수 있다.
이를 방지하려면 등록 여부를 먼저 확인할 수 있다.
if (!customElements.get('my-button')) {
customElements.define('my-button', MyButton);
}
customElements.get('my-button')은 이미 등록된 커스텀 요소가 있는지 확인한다.
등록되어 있지 않을 때만 define()을 실행하면 중복 등록 에러를 피할 수 있다.
12. Custom Elements에서 자주 하는 실수
Custom Elements를 사용할 때 자주 하는 실수는 다음과 같다.
- 태그 이름에 하이픈을 넣지 않는다.
- class만 만들고 customElements.define()을 호출하지 않는다.
- 같은 태그 이름을 중복 등록한다.
- attribute 값을 가져오기 전에 null 처리를 하지 않는다.
- connectedCallback()이 여러 번 실행될 수 있다는 점을 고려하지 않는다.
특히 태그 이름 규칙과 중복 등록 문제는 처음 만들 때 자주 발생한다.
13. 정리
AD
제휴 광고 · 일부 링크는 수수료를 받을 수 있습니다
Custom Elements는 Web Components의 가장 기본이 되는 기술이다.
- Custom Elements는 직접 HTML 태그를 만드는 기술이다.
- 커스텀 태그 이름에는 반드시 하이픈이 필요하다.
- 커스텀 요소 class는 HTMLElement를 상속받는다.
- customElements.define()으로 태그 이름과 class를 연결한다.
- connectedCallback()은 요소가 DOM에 추가될 때 실행된다.
- getAttribute()로 attribute 값을 가져올 수 있다.
- 한 번 정의한 커스텀 요소는 여러 번 재사용할 수 있다.
Custom Elements를 이해하면 Web Components의 기본 구조를 이해할 수 있다.
다음 Part에서는 Shadow DOM을 알아본다.
Shadow DOM은 컴포넌트 내부 구조와 스타일을 외부와 분리해서 스타일 충돌을 줄여주는 핵심 기술이다.
AD
제휴 광고
일부 링크는 제휴 링크이며, 구매 또는 가입 시 일정 수수료를 받을 수 있습니다.
AD
'Web components' 카테고리의 다른 글
전체보기- [Part 2] Web Components — Custom Elements 완전 정복 현재 글
- [Part 3] Web Components — Shadow DOM과 스타일 격리 2026.04.15
- [Part 4] Web Components — Template & Slot으로 유연한 구조 만들기 2026.04.22
- [Part 5] Web Components — Lifecycle Callbacks 완전 이해 2026.04.29
- [Part 6] Web Components — Custom Events와 컴포넌트 통신 2026.05.06
- [Part 7] Web Components — 고급 스타일링 전략 2026.05.13









