Raja Kode - Bottom Sheet digunakan pada aplikasi mobile sepanjang waktu. Mereka menawarkan cara sederhana untuk menampilkan informasi atau tindakan tambahan bila diperlukan.
Pada artikel ini, Raja Kode akan memberikan tutorial cara membuat Bottom Sheet terinspirasi iOS & Android yang dapat diseret, diaktifkan dengan sentuhan, dengan animasi slide halus pada halaman dengan menggunakan JavaScript biasa. Mari kita mulai.

Cara Memasang Bottom Sheet
1. Struktur HTML yang diperlukan untuk bottom sheet. Untuk Konten, bisa kamu sesuaikan sendiri sesuai kebutuhan:
<!-- The sheet component --> <div id="sheet" class="column items-center justify-end" aria-hidden="true"> <!-- Dark background for the sheet --> <div class="overlay"></div> <!-- The sheet itself --> <div class="contents column"> <!-- Sheet controls --> <header class="controls"> <!-- The thing to drag if you want to resize the sheet --> <div class="draggable-area"> <div class="draggable-thumb"></div> </div> <!-- Button to close the sheet --> <button class="close-sheet" type="button" title="Close the sheet">×</button> </header> <!-- Body of the sheet --> <main class="body fill column"> <h2>Hello, World!</h2> </main> </div> </div>
2. CSS inti untuk widget bottom sheet. Kamu bebas untuk mengkostumisasinya sesuai keinginan.
:root { --background: #fff; --foreground: #000; --divider: #dcdcdc; --overlay: #888; } @media (prefers-color-scheme: dark) { :root { --background: #000; --foreground: #fff; --divider: #333; } } #sheet { position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 2; visibility: visible; transition: opacity 0.5s, visibility 0.5s; } #sheet[aria-hidden="true"] { opacity: 0; visibility: hidden; pointer-events: none; } #sheet .overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: -1; background: var(--overlay); opacity: 0.5; } #sheet .contents { border-radius: 1rem 1rem 0 0; background: var(--background); position: relative; overflow-y: hidden; --default-transitions: transform 0.5s, border-radius 0.5s; transition: var(--default-transitions); transform: translateY(0); max-height: 100vh; height: 30vh; max-width: 70rem; box-sizing: border-box; padding: 1rem; padding-top: 3rem; } #sheet .contents:not(.not-selectable) { transition: var(--default-transitions), height 0.5s; } #sheet .contents.fullscreen { border-radius: 0; } #sheet[aria-hidden="true"] .contents { transform: translateY(100%); } #sheet .draggable-area { position: absolute; top: 0; left: 0; right: 0; width: 3rem; margin: auto; padding: 1rem; cursor: grab; } #sheet .draggable-thumb { width: inherit; height: 0.25rem; background: var(--divider); border-radius: 0.125rem; } #sheet .close-sheet { position: absolute; right: 0; top: 0; border: none; } #sheet .body { height: 100%; overflow-y: auto; gap: 1rem; }
3. JavaScript inti untuk mengaktifkan bottom sheet.
const $ = document.querySelector.bind(document) const sheet = $("#sheet") const sheetContents = sheet.querySelector(".contents") const draggableArea = sheet.querySelector(".draggable-area") let sheetHeight // in vh const setSheetHeight = (value) => { sheetHeight = Math.max(0, Math.min(100, value)) sheetContents.style.height = `${sheetHeight}vh` if (sheetHeight === 100) { sheetContents.classList.add("fullscreen") } else { sheetContents.classList.remove("fullscreen") } } const setIsSheetShown = (value) => { sheet.setAttribute("aria-hidden", String(!value)) } // Open the sheet when clicking the 'open sheet' button setSheetHeight(Math.min(50, 720 / window.innerHeight * 100)) setIsSheetShown(true) // Hide the sheet when clicking the 'close' button sheet.querySelector(".close-sheet").addEventListener("click", () => { setIsSheetShown(false) }) // Hide the sheet when clicking the background sheet.querySelector(".overlay").addEventListener("click", () => { setIsSheetShown(false) }) const touchPosition = (event) => event.touches ? event.touches[0] : event let dragPosition const onDragStart = (event) => { dragPosition = touchPosition(event).pageY sheetContents.classList.add("not-selectable") draggableArea.style.cursor = document.body.style.cursor = "grabbing" } const onDragMove = (event) => { if (dragPosition === undefined) return const y = touchPosition(event).pageY const deltaY = dragPosition - y const deltaHeight = deltaY / window.innerHeight * 100 setSheetHeight(sheetHeight + deltaHeight) dragPosition = y } const onDragEnd = () => { dragPosition = undefined sheetContents.classList.remove("not-selectable") draggableArea.style.cursor = document.body.style.cursor = "" if (sheetHeight < 25) { setIsSheetShown(false) } else if (sheetHeight > 75) { setSheetHeight(100) } else { setSheetHeight(50) } } draggableArea.addEventListener("mousedown", onDragStart) draggableArea.addEventListener("touchstart", onDragStart) window.addEventListener("mousemove", onDragMove) window.addEventListener("touchmove", onDragMove) window.addEventListener("mouseup", onDragEnd) window.addEventListener("touchend", onDragEnd)