useDisclosure
Composable headless state buka/tutup + ARIA props — dasar dari
Disclosure/SimpleDisclosure, diekspor langsung untuk UI custom penuh.
Bagian dari: vue-salayout · Family: Headless
Import
import { useDisclosure } from '@bpmlib/vue-salayout';Instalasi: lihat Installation & Setup di halaman utama.
Usage
<script setup lang="ts">
import { useDisclosure } from '@bpmlib/vue-salayout';
const { isOpen, toggle, triggerProps, panelProps } = useDisclosure({ defaultOpen: false });
</script>
<template>
<button v-bind="triggerProps" @click="toggle">{{ isOpen ? 'Tutup' : 'Buka' }}</button>
<div v-bind="panelProps" v-show="isOpen">Isi panel — markup sepenuhnya milik kamu.</div>
</template>Tidak ada CSS, tidak ada opini DOM, tidak ada ketergantungan ke Card sama sekali — cocok kalau kamu butuh membangun UI disclosure custom sepenuhnya, bukan sekadar styling ulang.
API Reference
useDisclosure
Mengelola state buka/tutup satu item disclosure, uncontrolled (state lokal) atau controlled (didelegasikan lewat controlledOpen/onToggle) — mekanisme yang sama dipakai Disclosure/SimpleDisclosure secara internal saat nested di dalam Accordion, atau saat dipakai dengan v-model.
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
options | UseDisclosureOptions | {} | Konfigurasi awal + hook controlled mode Lihat selengkapnya |
options
Structure:
interface UseDisclosureOptions {
defaultOpen?: boolean;
controlledOpen?: ComputedRef<boolean>;
onToggle?: () => void;
onOpen?: () => void;
onClose?: () => void;
onToggleState?: (isOpen: boolean) => void;
}Properties:
defaultOpen- Status awal untuk pemakaian uncontrolled. Default:falsecontrolledOpen- Kalau diisi, status open didelegasikan ke sini alih-alih dikelola lokal Lihat selengkapnyaonToggle- Dipanggil alih-alih mutasi state lokal saatcontrolledOpendiisi Lihat selengkapnyaonOpen/onClose- Fire di setiap transisi buka/tutup nyata (tidak pernah saat mount, meskidefaultOpen: true) Lihat selengkapnyaonToggleState- Fire bersamaan denganonOpen/onClose, dengan status baru Lihat selengkapnya
controlledOpen
Dipakai saat sesuatu di luar composable ini (parent Accordion, v-model component pembungkus) yang benar-benar memegang status open/close.
Signature:
controlledOpen?: ComputedRef<boolean>Contoh:
<script setup lang="ts">
import { ref, computed } from 'vue';
import { useDisclosure } from '@bpmlib/vue-salayout';
const externalOpen = ref(false);
const { isOpen, toggle } = useDisclosure({
controlledOpen: computed(() => externalOpen.value),
onToggle: () => (externalOpen.value = !externalOpen.value),
});
</script>Use Case: Membangun component pembungkus sendiri yang perlu koordinasi banyak instance sekaligus (pola yang sama dipakai Accordion untuk Disclosure/SimpleDisclosure).
onToggle
Signature:
onToggle?: () => voidDipanggil oleh toggle()/open()/close() sebagai ganti mutasi lokal, hanya saat controlledOpen diisi. open()/close() tidak memanggilnya kalau status sudah sesuai target (no-op).
Use Case: Titik satu-satunya tempat status eksternal benar-benar diubah, dipisah dari logic baca status (controlledOpen).
onOpen / onClose
Signature:
onOpen?: () => void
onClose?: () => voidContoh:
useDisclosure({
onOpen: () => console.log('Terbuka'),
onClose: () => console.log('Tertutup'),
});Use Case: Efek samping yang hanya perlu tahu arah transisi (mis. fokus elemen tertentu saat terbuka), tanpa peduli status barunya secara eksplisit.
onToggleState
Signature:
onToggleState?: (isOpen: boolean) => voidContoh:
useDisclosure({
onToggleState: (isOpen) => console.log('Status sekarang:', isOpen),
});Use Case: Analytics/tracking interaksi buka-tutup tanpa perlu membedakan onOpen/onClose secara terpisah.
Returns
Contains:
isOpen
isOpen: ComputedRef<boolean>Status open/close saat ini — dari state lokal atau controlledOpen, tergantung mode.
⚠️ Penting - Penggunaan .value:
- Di
<script>: Perlu.value→isOpen.value - Di
<template>: Tidak perlu.value(auto-unwrap) →isOpen
toggle, open, close
toggle: () => void
open: () => void
close: () => voidMutasi state lokal langsung (uncontrolled), atau delegasi ke onToggle (controlled) — lihat controlledOpen.
Contoh:
const { isOpen, toggle, open, close } = useDisclosure();
toggle(); // buka jika tertutup, tutup jika terbuka
open(); // paksa terbuka
close(); // paksa tertutuptriggerProps
triggerProps: ComputedRef<{ 'aria-expanded': boolean; 'aria-controls': string }>Di-spread langsung ke elemen trigger custom kamu (v-bind="triggerProps").
panelProps
panelProps: ComputedRef<{ id: string }>Di-spread langsung ke elemen panel custom kamu (v-bind="panelProps") — id-nya sama dengan yang dirujuk triggerProps's aria-controls.
Digunakan oleh: Disclosure, SimpleDisclosure
Kapan pakai langsung: Gunakan composable ini langsung kalau kamu butuh markup/CSS custom penuh yang tidak bisa dicapai lewat slot trigger/caret/list/children milik Disclosure/SimpleDisclosure. Kalau default styling kedua component itu sudah cukup, pakai component stylized-nya saja.
Examples
1. Uncontrolled Dasar
<script setup lang="ts">
import { useDisclosure } from '@bpmlib/vue-salayout';
const { isOpen, toggle, triggerProps, panelProps } = useDisclosure();
</script>
<template>
<button v-bind="triggerProps" @click="toggle">Toggle</button>
<div v-bind="panelProps" v-show="isOpen">Konten.</div>
</template>2. Programmatic open()/close() Tanpa Trigger
<script setup lang="ts">
import { useDisclosure } from '@bpmlib/vue-salayout';
const { isOpen, open, close, panelProps } = useDisclosure();
</script>
<template>
<button @click="open()">Buka</button>
<button @click="close()">Tutup</button>
<div v-bind="panelProps" v-show="isOpen">Konten.</div>
</template>Related Components
- Disclosure — stylized, memakai composable ini secara internal
- SimpleDisclosure — stylized, memakai composable ini secara internal