Tujuan inisiatif Open UI adalah mempermudah developer menciptakan pengalaman pengguna yang hebat. Untuk melakukannya, kami mencoba mengatasi pola yang lebih bermasalah yang dihadapi developer. Kita dapat melakukannya dengan menyediakan API dan komponen bawaan platform yang lebih baik.
Salah satu area masalah tersebut adalah pop-up, yang dijelaskan di Open UI sebagai "Popovers".
Popover telah lama memiliki reputasi yang cukup kontroversial. Hal ini sebagian disebabkan oleh cara pembuatan dan deployment keduanya. Pola ini tidak mudah dibuat dengan baik, tetapi dapat menghasilkan banyak nilai dengan mengarahkan pengguna ke hal-hal tertentu, atau membuat mereka mengetahui konten di situs Anda—terutama jika digunakan dengan cara yang menarik.
Sering kali ada dua masalah utama saat membuat popover:
- Cara memastikan penempatannya di atas konten lainnya di tempat yang sesuai.
- Cara membuatnya dapat diakses (kompatibel dengan keyboard, dapat difokuskan, dan sebagainya).
Popover API bawaan memiliki berbagai tujuan, semuanya dengan tujuan utama yang sama, yaitu memudahkan developer membangun pola ini. Sasaran yang paling penting adalah:
- Memudahkan menampilkan elemen dan turunannya di atas bagian dokumen lainnya.
- Buat agar mudah diakses.
- Tidak memerlukan JavaScript untuk perilaku paling umum (tutup ringan, singleton, penumpukan, dan sebagainya).
Anda dapat melihat spesifikasi lengkap untuk pop-up di situs OpenUI.
Kompatibilitas browser
Di mana Anda dapat menggunakan Popover API bawaan sekarang? Fitur ini didukung di Chrome Canary di balik tanda "Fitur platform web eksperimental" pada saat penulisan.
Untuk mengaktifkan tanda tersebut, buka Chrome Canary dan kunjungi chrome://flags. Kemudian, aktifkan tanda "Fitur platform web eksperimental".
Ada juga Uji Coba Origin untuk developer yang ingin mengujinya di lingkungan produksi.
Terakhir, ada polyfill yang sedang dikembangkan untuk API. Pastikan untuk melihat repo di github.com/oddbird/popup-polyfill.
Anda dapat memeriksa dukungan pop-up dengan:
const supported = HTMLElement.prototype.hasOwnProperty("popover");
Solusi saat ini
Apa yang dapat Anda lakukan saat ini untuk mempromosikan konten Anda di atas segalanya? Jika didukung di browser Anda, Anda dapat menggunakan elemen Dialog HTML. Anda harus menggunakannya dalam bentuk "Modal". Dan ini memerlukan JavaScript untuk digunakan.
Dialog.showModal();
Ada beberapa pertimbangan aksesibilitas. Sebaiknya gunakan a11y-dialog misalnya jika melayani pengguna Safari di bawah versi 15.4.
Anda juga dapat menggunakan salah satu dari banyak library berbasis popover, pemberitahuan, atau tooltip yang tersedia. Sebagian besar aplikasi ini cenderung berfungsi dengan cara yang serupa.
- Tambahkan beberapa penampung ke isi untuk menampilkan popover.
- Gaya sehingga berada di atas semuanya.
- Buat elemen dan tambahkan ke penampung untuk menampilkan popover.
- Sembunyikan dengan menghapus elemen popover dari DOM.
Hal ini memerlukan dependensi tambahan dan lebih banyak keputusan bagi developer. Anda juga perlu melakukan riset untuk menemukan penawaran yang menyediakan semua yang Anda butuhkan. Popover API bertujuan untuk mengakomodasi banyak skenario, termasuk tooltip. Tujuannya adalah untuk mencakup semua skenario umum tersebut, sehingga developer tidak perlu membuat keputusan lain dan dapat berfokus pada pembuatan pengalaman mereka.
Pop-up pertama Anda
Ini saja yang Anda butuhkan.
<div id="my-first-popover" popover>Popover Content!</div>
<button popovertoggletarget="my-first-popover">Toggle Popover</button>
Namun, apa yang terjadi di sini?
- Anda tidak perlu memasukkan elemen popover ke dalam penampung atau apa pun—elemen ini disembunyikan secara default.
- Anda tidak perlu menulis JavaScript apa pun agar muncul. Hal itu ditangani oleh atribut
popovertoggletarget. - Saat muncul, item tersebut akan dipromosikan ke lapisan atas. Artinya, item tersebut dipromosikan di atas
documentdi area pandang. Anda tidak perlu mengelolaz-indexatau mengkhawatirkan posisi popover di DOM. Elemen ini dapat berada jauh di dalam DOM, dengan elemen induk yang memotong. Anda juga dapat melihat elemen mana yang saat ini berada di lapisan atas melalui DevTools. Untuk mengetahui informasi selengkapnya tentang lapisan atas, baca artikel ini.

- Anda mendapatkan "Penutupan Ringan" langsung. Dengan demikian, Anda dapat menutup popover dengan sinyal penutupan, seperti mengklik di luar popover, menavigasi keyboard ke elemen lain, atau menekan tombol Esc. Buka lagi dan coba.
Apa lagi yang Anda dapatkan dengan popover? Mari kita lanjutkan contohnya. Pertimbangkan demo ini dengan beberapa konten di halaman.
Tombol tindakan mengambang tersebut memiliki posisi tetap dengan z-index yang tinggi.
.fab {
position: fixed;
z-index: 99999;
}
Konten popover disematkan di DOM, tetapi saat Anda membuka popover, konten tersebut akan dipromosikan di atas elemen posisi tetap tersebut. Anda tidak perlu menyetel gaya apa pun.
Anda juga dapat melihat bahwa popover kini memiliki elemen semu ::backdrop. Semua elemen yang berada di lapisan atas mendapatkan elemen semu ::backdrop yang dapat diberi gaya. Contoh ini menata gaya ::backdrop dengan warna latar belakang alfa yang dikurangi dan filter latar, yang mengaburkan konten di bawahnya.
Menata gaya popover
Sekarang kita beralih ke penataan gaya popover. Secara default, popover memiliki posisi tetap dan beberapa padding yang diterapkan. Selain itu, juga memiliki display: none. Anda dapat mengganti setelan ini untuk menampilkan popover. Namun, hal itu tidak akan mempromosikannya ke lapisan atas.
[popover] { display: block; }
Terlepas dari cara Anda mempromosikan popover, setelah mempromosikan popover ke lapisan atas, Anda mungkin perlu menata atau memosisikannya. Anda tidak dapat menargetkan lapisan atas dan melakukan sesuatu seperti
:open {
display: grid;
place-items: center;
}
Secara default, popover akan ditata di tengah area tampilan menggunakan margin: auto. Namun, dalam beberapa kasus, Anda mungkin ingin menentukan posisi secara eksplisit. Contoh:
[popover] {
top: 50%;
left: 50%;
translate: -50%;
}
Jika Anda ingin menata konten di dalam popover menggunakan petak CSS atau flexbox, sebaiknya bungkus konten ini dalam elemen. Jika tidak, Anda harus mendeklarasikan aturan terpisah yang mengubah display setelah popover berada di lapisan atas. Menyetelnya secara default akan membuatnya ditampilkan secara default, menggantikan display: none.
[popover]:open {
display: flex;
}
Jika Anda mencoba demo tersebut, Anda akan melihat bahwa popover kini bertransisi masuk dan keluar. Anda dapat membuat popover muncul dan menghilang menggunakan pseudo-selektor :open. Pseudo-selector :open cocok dengan popover yang ditampilkan (dan oleh karena itu berada di lapisan atas).
Contoh ini menggunakan properti kustom untuk mendorong transisi. Anda juga dapat menerapkan transisi ke ::backdrop popover.
[popover] {
--hide: 1;
transition: transform 0.2s;
transform: translateY(calc(var(--hide) * -100vh))
scale(calc(1 - var(--hide)));
}
[popover]::backdrop {
transition: opacity 0.2s;
opacity: calc(1 - var(--hide, 1));
}
[popover]:open::backdrop {
--hide: 0;
}
Tipsnya di sini adalah mengelompokkan transisi dan animasi dalam kueri media untuk gerakan. Cara ini juga dapat membantu menjaga waktu Anda. Hal ini karena Anda tidak dapat membagikan nilai antara popover dan ::backdrop melalui properti kustom.
@media(prefers-reduced-motion: no-preference) {
[popover] { transition: transform 0.2s; }
[popover]::backdrop { transition: opacity 0.2s; }
}
Hingga saat ini, Anda telah melihat penggunaan popovertoggletarget untuk menampilkan popover. Untuk menutupnya, kita menggunakan "Penutupan ringan". Namun, Anda juga mendapatkan atribut popovershowtarget dan popoverhidetarget yang dapat digunakan. Mari tambahkan tombol ke popover yang menyembunyikannya dan ubah tombol untuk menggunakan popovershowtarget.
<div id="code-popover" popover>
<button popoverhidetarget="code-popover">Hide Code</button>
</div>
<button popovershowtarget="code-popover">Reveal Code</button>
Seperti yang disebutkan sebelumnya, Popover API mencakup lebih dari sekadar gagasan historis kita tentang pop-up. Anda dapat membangun untuk semua jenis skenario seperti notifikasi, menu, tooltip, dll.
Beberapa skenario tersebut memerlukan pola interaksi yang berbeda. Interaksi seperti mengarahkan kursor. Penggunaan atribut popoverhovertarget telah diuji, tetapi saat ini belum diterapkan.
<div popoverhovertarget="hover-popover">Hover for Code</div>
Idenya adalah Anda mengarahkan kursor ke elemen untuk menampilkan target. Perilaku ini dapat dikonfigurasi melalui properti CSS. Properti CSS ini akan menentukan jangka waktu untuk mengarahkan kursor ke dan dari elemen yang direspons popover. Perilaku default yang diuji coba menampilkan popover setelah 0.5s :hover yang eksplisit. Kemudian, popover tersebut memerlukan penutupan ringan atau pembukaan popover lain untuk ditutup (Info selengkapnya akan dibahas nanti). Hal ini disebabkan oleh durasi penyembunyian popover yang ditetapkan ke Infinity.
Sementara itu, Anda dapat menggunakan JavaScript untuk mem-polyfill fungsi tersebut.
let hoverTimer;
const HOVER_TRIGGERS = document.querySelectorAll("[popoverhovertarget]");
const tearDown = () => {
if (hoverTimer) clearTimeout(hoverTimer);
};
HOVER_TRIGGERS.forEach((trigger) => {
const popover = document.querySelector(
`#${trigger.getAttribute("popoverhovertarget")}`
);
trigger.addEventListener("pointerenter", () => {
hoverTimer = setTimeout(() => {
if (!popover.matches(":open")) popover.showPopover();
}, 500);
trigger.addEventListener("pointerleave", tearDown);
});
});
Manfaat menyetel sesuatu sebagai jendela keaktifan eksplisit adalah untuk memastikan tindakan pengguna disengaja (misalnya, pengguna mengarahkan kursor ke target). Kita tidak ingin menampilkan pop-up kecuali jika itu memang keinginan pengguna.
Coba demo ini tempat Anda dapat mengarahkan kursor ke target dengan jendela yang disetel ke 0.5s.
Sebelum membahas beberapa kasus penggunaan dan contoh umum, mari kita bahas beberapa hal.
Jenis popover
Kita telah membahas perilaku interaksi non-JavaScript. Namun, bagaimana dengan perilaku popover secara keseluruhan. Bagaimana jika Anda tidak menginginkan "Tutup ringan"? Atau Anda ingin menerapkan pola singleton ke popover?
Popover API memungkinkan Anda menentukan tiga jenis popover yang berbeda dalam perilaku.
[popover=auto]/[popover]:
- Dukungan penyusunan. Hal ini tidak hanya berarti bersarang di DOM. Definisi popover ancestor adalah popover yang:
- terkait dengan posisi DOM (turunan).
- terkait dengan memicu atribut pada elemen turunan seperti
popovertoggletarget,popovershowtarget, dan sebagainya. - terkait dengan atribut
anchor(CSS Anchoring API dalam pengembangan).
- Penutupan ringan.
- Membuka akan menutup popover lain yang bukan popover turunan. Coba demo di bawah yang menunjukkan cara kerja penyusunan dengan popover turunan. Lihat bagaimana perubahan beberapa instance
popoverhidetarget/popovershowtargetmenjadipopovertoggletargetmengubah keadaan. - Menutup satu notifikasi akan menutup semua notifikasi, tetapi menutup satu notifikasi dalam tumpukan hanya akan menutup notifikasi di atasnya dalam tumpukan.
[popover=manual]:
- Tidak menutup popover lainnya.
- Tutup tanpa cahaya.
- Memerlukan penutupan eksplisit melalui elemen pemicu atau JavaScript.
JavaScript API
Jika Anda memerlukan kontrol yang lebih besar atas popover, Anda dapat menggunakan JavaScript. Anda akan mendapatkan metode showPopover dan hidePopover. Anda juga memiliki peristiwa popovershow dan popoverhide yang perlu diproses:
Menampilkan popover
js
popoverElement.showPopover()
Menyembunyikan popover:
popoverElement.hidePopover()
Memantau apakah popover ditampilkan:
popoverElement.addEventListener('popovershow', doSomethingWhenPopoverShows)
Pantau popover yang ditampilkan dan batalkan penampilannya:
popoverElement.addEventListener('popovershow',event => {
event.preventDefault();
console.warn(‘We blocked a popover from being shown’);
})
Mendengarkan popover yang disembunyikan:
popoverElement.addEventListener('popoverhide', doSomethingWhenPopoverHides)
Anda tidak dapat membatalkan popover yang disembunyikan:
popoverElement.addEventListener('popoverhide',event => {
event.preventDefault();
console.warn("You aren't allowed to cancel the hiding of a popover");
})
Periksa apakah popover berada di lapisan atas:
popoverElement.matches(':open')
Hal ini memberikan daya ekstra untuk beberapa skenario yang kurang umum. Misalnya, tampilkan popover setelah periode tidak ada aktivitas.
Demo ini memiliki popover dengan bunyi pop yang terdengar, jadi kita memerlukan JavaScript untuk memutar audio. Saat diklik, kita menyembunyikan popover, memutar audio, lalu menampilkannya lagi.
Aksesibilitas
Aksesibilitas menjadi prioritas utama saat menggunakan Popover API. Pemetaan aksesibilitas mengaitkan popover dengan elemen pemicunya, sesuai kebutuhan. Artinya, Anda tidak perlu mendeklarasikan atribut aria-* seperti aria-haspopup, dengan asumsi Anda menggunakan salah satu atribut pemicu seperti popovertoggletarget.
Untuk pengelolaan fokus, Anda dapat menggunakan atribut fokus otomatis untuk memindahkan fokus ke elemen di dalam popover. Hal ini sama seperti untuk Dialog, tetapi perbedaannya muncul saat mengembalikan fokus, dan hal itu karena penutupan ringan. Dalam sebagian besar kasus, menutup popover akan mengembalikan fokus ke elemen yang sebelumnya difokuskan. Namun, fokus dipindahkan ke elemen yang diklik saat penutupan ringan, jika elemen tersebut dapat menerima fokus. Lihat bagian tentang pengelolaan fokus dalam penjelasan.
Anda harus membuka "versi layar penuh" demo ini untuk melihat cara kerjanya.
Dalam demo ini, elemen yang difokuskan akan mendapatkan garis batas berwarna hijau. Coba menjelajahi antarmuka dengan keyboard Anda. Perhatikan tempat fokus dikembalikan saat popover ditutup. Anda mungkin juga memperhatikan bahwa jika Anda berpindah tab, popover akan ditutup. Hal ini sesuai dengan desain. Meskipun memiliki pengelolaan fokus, popover tidak menjebak fokus. Selain itu, navigasi keyboard mengidentifikasi sinyal tutup saat fokus berpindah dari popover.
Penjangkaran (dalam pengembangan)
Untuk popover, pola rumit yang harus diakomodasi adalah menyematkan elemen ke pemicunya. Misalnya, jika tooltip disetel untuk ditampilkan di atas pemicunya, tetapi dokumen digulir. Tips tersebut dapat terpotong oleh area tampilan. Ada penawaran JavaScript saat ini untuk mengatasi hal ini seperti "Floating UI". Mereka akan memosisikan ulang tooltip agar hal ini tidak terjadi dan mengandalkan urutan posisi yang diinginkan.
Namun, kami ingin Anda dapat menentukannya dengan gaya Anda. Ada API pendamping yang sedang dikembangkan bersama dengan Popover API untuk mengatasi hal ini. API "CSS Anchor Positioning" akan memungkinkan Anda mengikat elemen ke elemen lain, dan akan melakukannya dengan cara yang memosisikan ulang elemen sehingga tidak terpotong oleh viewport.
Demo ini menggunakan Anchoring API dalam statusnya saat ini. Posisi perahu merespons posisi penanda di area pandang.
Berikut cuplikan CSS yang membuat demo ini berfungsi. Tidak memerlukan JavaScript.
.anchor {
--anchor-name: --anchor;
}
.anchored {
position: absolute;
position-fallback: --compass;
}
@position-fallback --compass {
@try {
bottom: anchor(--anchor top);
left: anchor(--anchor right);
}
@try {
top: anchor(--anchor bottom);
left: anchor(--anchor right);
}
}
Anda dapat melihat spesifikasinya di sini. Akan ada juga polyfill untuk API ini.
Contoh
Sekarang Anda sudah memahami apa yang ditawarkan popover dan caranya, mari kita pelajari beberapa contohnya.
Notifikasi
Demo ini menampilkan notifikasi "Salin ke papan klip".
- Menggunakan
[popover=manual]. - Pada tindakan, tampilkan popover dengan
showPopover. - Setelah waktu tunggu
2000ms, sembunyikan denganhidePopover.
Toast
Demo ini menggunakan lapisan atas untuk menampilkan notifikasi gaya toast.
- Satu popover dengan jenis
manualbertindak sebagai penampung. - Notifikasi baru ditambahkan ke popover dan popover ditampilkan.
- Elemen tersebut dihapus dengan web animations API saat diklik dan dihapus dari DOM.
- Jika tidak ada toast yang ditampilkan, popover akan disembunyikan.
Menu bertingkat
Demo ini menunjukkan cara kerja menu navigasi bertingkat.
- Gunakan
[popover=auto]karena memungkinkan popover bertingkat. - Gunakan
autofocuspada link pertama setiap dropdown untuk menavigasi keyboard. - Ini adalah kandidat yang tepat untuk CSS Anchoring API. Namun, untuk demo ini, Anda dapat menggunakan sedikit JavaScript untuk memperbarui posisi menggunakan properti kustom.
const ANCHOR = (anchor, anchored) => () => {
const { top, bottom, left, right } = anchor.getBoundingClientRect();
anchored.style.setProperty("--top", top);
anchored.style.setProperty("--right", right);
anchored.style.setProperty("--bottom", bottom);
anchored.style.setProperty("--left", left);
};
PRODUCTS_MENU.addEventListener("popovershow", ANCHOR(PRODUCT_TARGET, PRODUCTS_MENU));
Ingat, karena demo ini menggunakan autofocus, demo ini harus dibuka dalam "tampilan layar penuh" untuk navigasi keyboard.
Popover media
Demo ini menunjukkan cara Anda memunculkan media.
- Menggunakan
[popover=auto]untuk menutup notifikasi ringan. - JavaScript memproses peristiwa
playvideo dan memunculkan video. - Peristiwa
popoverhidepopover menjeda video.
Popover gaya wiki
Demo ini menunjukkan cara membuat tooltip konten inline yang berisi media.
- Menggunakan
[popover=auto]. Menampilkan satu akan menyembunyikan yang lain karena tidak bersifat leluhur. - Ditampilkan di
pointerenterdengan JavaScript. - Kandidat sempurna lainnya untuk CSS Anchoring API.
Panel Samping Navigasi
Demo ini membuat panel navigasi menggunakan popover.
- Menggunakan
[popover=auto]untuk menutup notifikasi ringan. - Menggunakan
autofocusuntuk memfokuskan item navigasi pertama.
Mengelola latar
Demo ini menunjukkan cara Anda mengelola latar belakang untuk beberapa popover yang hanya ingin Anda tampilkan satu ::backdrop.
- Gunakan JavaScript untuk mempertahankan daftar popover yang terlihat.
- Terapkan nama class ke popover terendah di lapisan atas.
Popover kursor kustom
Demo ini menunjukkan cara menggunakan popover untuk mempromosikan canvas ke lapisan teratas dan menggunakannya untuk menampilkan kursor kustom.
- Promosikan
canvaske lapisan atas denganshowPopoverdan[popover=manual]. - Saat popover lain dibuka, sembunyikan dan tampilkan popover
canvasuntuk memastikan popover tersebut berada di atas.
Popover sheet tindakan
Demo ini menunjukkan cara menggunakan popover sebagai sheet tindakan.
- Menampilkan popover secara default yang menggantikan
display. - Actionsheet dibuka dengan pemicu popover.
- Saat ditampilkan, popover akan dipromosikan ke lapisan teratas dan diterjemahkan ke dalam tampilan.
- Penutupan ringan dapat digunakan untuk mengembalikannya.
Popover yang diaktifkan keyboard
Demo ini menunjukkan cara Anda dapat menggunakan popover untuk UI gaya palet perintah.
- Gunakan cmd + j untuk menampilkan popover.
inputdifokuskan denganautofocus.- Kotak kombinasi adalah
popoverkedua yang diposisikan di bawah input utama. - Penutupan ringan akan menutup palet jika dropdown tidak ada.
- Kandidat lain untuk Anchoring API
Popover berjangka waktu
Demo ini menampilkan popover tidak aktif setelah empat detik. Pola UI yang sering digunakan di aplikasi yang menyimpan informasi aman tentang pengguna untuk menampilkan modal logout.
- Gunakan JavaScript untuk menampilkan popover setelah periode tidak ada aktivitas.
- Saat popover ditampilkan, reset timer.
Screensaver
Mirip dengan demo sebelumnya, Anda dapat menambahkan sentuhan unik ke situs dan menambahkan screensaver.
- Gunakan JavaScript untuk menampilkan popover setelah periode tidak ada aktivitas.
- Tutup ringan untuk menyembunyikan dan mereset timer.
Mengikuti tanda sisipan
Demo ini menunjukkan cara agar popover mengikuti kursor input.
- Tampilkan popover berdasarkan pilihan, peristiwa utama, atau input karakter khusus.
- Gunakan JavaScript untuk memperbarui posisi popover dengan properti kustom yang tercakup.
- Pola ini memerlukan pemikiran yang matang terhadap konten yang ditampilkan dan aksesibilitas.
- Tombol ini sering terlihat di UI pengeditan teks dan aplikasi tempat Anda dapat memberi tag.
Menu tombol tindakan mengambang
Demo ini menunjukkan cara Anda dapat menggunakan popover untuk menerapkan menu tombol tindakan mengambang tanpa JavaScript.
- Promosikan popover jenis
manualdengan metodeshowPopover. Ini adalah tombol utama. - Menu adalah popover lain yang menjadi target tombol utama.
- Menu dibuka dengan
popovertoggletarget. - Gunakan
autofocusuntuk memfokuskan item menu pertama yang ditampilkan. - Penutupan ringan akan menutup menu.
- Putaran ikon menggunakan
:has(). Anda dapat membaca selengkapnya tentang:has()di artikel ini.
Selesai!
Jadi, itulah pengantar popover, yang akan hadir sebagai bagian dari inisiatif Open UI. Jika digunakan dengan bijak, fitur ini akan menjadi tambahan yang luar biasa untuk platform web.
Pastikan untuk melihat Open UI. Penjelasan popover terus diperbarui seiring perkembangan API. Berikut kumpulan semua demo.
Terima kasih sudah mampir!