Đàn phong cầm độc quyền

Tạo một trình đơn accordion độc quyền có nhiều phần tử <details> có cùng một name.

Accordion

Một mẫu giao diện người dùng phổ biến trên web là thành phần xếp nếp. Đây là một thành phần bao gồm một số tiện ích thông tin công bố có thể được mở rộng (hoặc thu gọn) riêng lẻ để hiển thị (hoặc ẩn) nội dung của chúng.

Để triển khai mẫu này trên web, bạn kết hợp một vài phần tử <details> và thường nhóm các phần tử đó lại với nhau để cho biết rằng chúng thuộc cùng một nhóm.

Bản minh hoạ: Accordion bằng HTML và CSS.

Danh sách xếp dọc độc quyền

Browser Support

  • Chrome: 120.
  • Edge: 120.
  • Firefox: 130.
  • Safari: 17.2.

Một biến thể của mẫu accordion là accordion độc quyền, trong đó chỉ có thể mở một trong các tiện ích công bố cùng một lúc.

Để tạo một trình đơn accordion độc quyền trên web, bạn thêm thuộc tính name vào các phần tử <details>. Khi sử dụng thuộc tính này, nhiều phần tử <details> có cùng giá trị name sẽ tạo thành một nhóm ngữ nghĩa và các phần tử này sẽ hoạt động như một ngăn xếp độc quyền. Khi bạn mở một trong các phần tử <details> của nhóm, phần tử đã mở trước đó sẽ tự động đóng.

<details name="learn-css">
  <summary>Welcome to Learn CSS!</summary>
  <p>…</p>
</details>
<details name="learn-css">
  <summary>Box Model</summary>
  <p>…</p>
</details>
<details name="learn-css">
  <summary>Selectors</summary>
  <p>…</p>
</details>
Bản minh hoạ: Accordion độc quyền bằng HTML và CSS.

Một trang có thể có nhiều ngăn xếp độc quyền. Bất cứ khi nào bạn sử dụng giá trị name mới trên phần tử <details>, một nhóm logic mới sẽ được tạo.

Bản minh hoạ: Nhiều ngăn xếp độc quyền bằng HTML và CSS.

Các phần tử <details> thuộc một ngăn xếp độc quyền không nhất thiết phải là phần tử đồng cấp. Các phần tử này có thể nằm rải rác trong tài liệu. Thuộc tính name là thuộc tính nhóm các thành phần này, chứ không phải thứ tự DOM của các thành phần đó.

Thêm tính năng tự động điền cho danh sách xếp dọc độc quyền

Với JavaScript sau đây, bạn có thể polyfill hành vi của accordion độc quyền. Mã này dựa vào sự kiện toggle của phần tử <details>.

Khi một phần tử <details>name mở ra, mã sẽ tìm các phần tử <details> đang mở khác có cùng giá trị cho thuộc tính name và đóng các phần tử đó.

document.querySelectorAll("details[name]").forEach(($details) => {
  $details.addEventListener("toggle", (e) => {
    const name = $details.getAttribute("name");

    if (e.newState == "open") {
      document
        .querySelectorAll(`details[name=${name}][open]`)
        .forEach(($openDetails) => {
          if (!($openDetails === $details)) {
            $openDetails.removeAttribute("open");
          }
        });
    }
  });
});

Một số phiên bản trình duyệt cũ không kích hoạt sự kiện toggle này. Trong những trình duyệt đó, mã polyfill sẽ không làm gì cả. Về tính năng cải tiến dần, đây là hành vi được chấp nhận.