blog.dopana

Back

Web Components là tiêu chuẩn browser cho phép tạo reusable component — không cần framework nào.

<!-- Dùng component — chỉ là HTML tag -->
<star-rating value="4" max="5"></star-rating>
<user-avatar src="/avatar.jpg" size="large"></user-avatar>
<confirm-dialog>
  Bạn chắc chắn muốn xoá?
</confirm-dialog>
html

Chạy trong mọi browser hiện đại, kết hợp được với React/Vue/Svelte/Astro.

Core Technologies#

Web Components gồm 3 tiêu chuẩn:

Custom Elements  →  Định nghĩa HTML tag mới
Shadow DOM       →  Encapsulation (style + DOM riêng)
HTML Templates   →  Declarative markup (slot, template)
plaintext

Custom Elements#

Định nghĩa#

Dùng#

<star-rating value="3" max="5"></star-rating>

<script>
  document.querySelector('star-rating')
    .addEventListener('rate', (e) => {
      console.log('Rated:', e.detail)
    })
</script>
html

Lifecycle#

Shadow DOM#

Shadow DOM cô lập style và DOM — không bị ảnh hưởng bởi CSS global.

<!-- CSS global không ảnh hưởng đến card -->
<style>
  .card { background: red; }  /* Không ảnh hưởng */
  img { filter: blur(10px); } /* Không ảnh hưởng */
</style>

<user-card name="Alice" avatar="/alice.jpg">
  <span slot="role">Admin</span>
</user-card>
html

Slots#

Slot cho phép component nhận children từ bên ngoài:

<confirm-dialog title="Delete Post" id="dialog">
  <p>Bạn có chắc muốn xoá bài viết này?</p>
  <p style="color: red;">Hành động này không thể hoàn tác.</p>
</confirm-dialog>

<script>
  const dialog = document.getElementById('dialog')
  dialog.addEventListener('confirm', () => deletePost(postId))
  dialog.addEventListener('cancel', () => console.log('Cancelled'))
</script>
html

HTML Template#

class TooltipElement extends HTMLElement {
  connectedCallback() {
    const template = document.getElementById('tooltip-template')
    const clone = template.content.cloneNode(true)
    this.appendChild(clone)

    const text = this.getAttribute('text') || ''
    this.querySelector('.tooltip').textContent = text
  }
}

customElements.define('tooltip-element', TooltipElement)
javascript

State Management#

Tích Hợp Với Framework#

Web Components tương thích mọi framework:

// React — dùng như HTML tag thường
function App() {
  return (
    <div>
      <star-rating value={rating} max={5}
        onRate={(e) => setRating(e.detail)}
      />
      <user-card name="Alice" avatar="/alice.jpg" />
    </div>
  )
}
tsx
<!-- Svelte -->
<counter-element
  on:change={(e) => count = e.detail}
/>
svelte
<!-- Astro — zero JS mặc định -->
---
import Layout from '../layouts/Layout.astro'
---

<Layout>
  <star-rating value="4" max="5" />
  <user-card name="Alice" avatar="/alice.jpg">
    <span slot="role">Admin</span>
  </user-card>
</Layout>
astro

Lit — Thư Viện Cho Web Components#

Lit giúp viết Web Components dễ hơn:

<my-button variant="danger">Delete</my-button>
html

Khi Nào Dùng Web Components?#

✅ Nên dùng#

  • Design system / Component library — dùng được mọi framework
  • Micro-frontend — team khác nhau dùng framework khác nhau
  • Embedded widget — third-party widget chạy trong trang bất kỳ
  • Legacy app — thêm component mới vào app jQuery/SPA cũ
  • Framework-agnostic library — muốn ai cũng dùng được

❌ Không nên#

  • App chính — React/Vue/Svelte có developer experience tốt hơn
  • Complex state — Web Components không có state management built-in
  • SSR — Web Components cần JavaScript để hydrate
  • Small team, one framework — không cần abstraction này

Tổng Kết#

Web Components là tiêu chuẩn, không phải thư viện. Nó giải quyết bài toán “component dùng được ở mọi nơi”.

// Web Component — 3 API, không dependency
customElements.define('my-component', MyComponent)
this.attachShadow({ mode: 'open' })
<slot></slot>
javascript
Tiêu chíReact/Vue/SvelteWeb Components
Dependencies~10-40KB runtime0KB — browser API
HọcFramework-specificHTML/CSS/JS thuần
ReuseCùng frameworkMọi framework
SSR❌ (cần JS)
Shadow DOM✅ Native
StateBuilt-inTự làm
Build stepCó thể không cần

Web Components không thay thế framework — nó là lớp tương thích giữa các framework. Dùng cho component dùng chung, design system, widget third-party.

Tài liệu tham khảo#