Appearance
Vue useShowHide Composable
A reactive model for toggling UI visibility with an optional value. Useful for dialogs, drawers, and other overlay components that need to know what to show when they open — for example, the ID of an entity to edit.
When to use
Use this composable for any overlay that needs to know what to display when it opens — for example, passing an entity ID to an edit dialog. It pairs visibility state with an associated value and resets both on hide.
The pattern
Create a show/hide model with useShowHide(). Call show(value) to open an overlay and pass context; call hide() to close and reset.
Edit dialog
Pass the entity ID when showing the dialog. The dialog component reads the value to know what to load.
vue
<script setup>
import { useShowHide } from "./use-show-hide.js";
const editDialog = useShowHide();
function editUser(userId) {
editDialog.show(userId);
}
</script>
<template>
<button
v-for="user in users"
@click="editUser(user.id)"
>
Edit {{ user.name }}
</button>
<EditUserDialog
v-if="editDialog.visible"
:userId="editDialog.value"
@close="editDialog.hide()"
/>
</template>Confirmation dialog
Pass an entire object when the dialog needs multiple properties from the item.
vue
<script setup>
const confirmDelete = useShowHide();
</script>
<template>
<button @click="confirmDelete.show(item)">
Delete
</button>
<ConfirmDialog
v-if="confirmDelete.visible"
:message="`Delete ${confirmDelete.value.name}?`"
@confirm="deleteItem(confirmDelete.value.id)"
@cancel="confirmDelete.hide()"
/>
</template>Implementing the ShowHideModel
A ShowHideModel class holds visible and value state. The constructor returns a reactive() proxy. show(value) sets both properties; hide() resets them.
javascript
import { reactive } from "vue";
class ShowHideModel {
visible = false;
value = undefined;
constructor(options = {}) {
if (options.visible !== undefined) {
this.visible = options.visible;
}
if (options.value !== undefined) {
this.value = options.value;
}
return reactive(this);
}
show(value) {
this.value = value;
this.visible = true;
}
hide() {
this.visible = false;
this.value = undefined;
}
}
export function useShowHide(options = {}) {
return new ShowHideModel(options);
}Reactive proxy from constructor
Like other Vue class-based composables, the constructor returns reactive(this), making all properties reactive without wrapping each in ref().
The value property for context
The value property carries context to the shown UI. For an edit dialog, pass the entity ID: dialog.show(entityId). The dialog component reads dialog.value to know what to load. When hiding, value resets to undefined, preventing stale data from leaking into the next show() call.
Trade-offs
- Single value only —
show()accepts one argument. To pass multiple values, use an object:dialog.show({ id, mode }). - No transition support — The model tracks boolean visibility. CSS transitions or Vue
<Transition>need to be handled in the template, not the model. - No open/close callbacks — The model doesn't emit events or run callbacks on state change. If you need side effects on show/hide (like fetching data), watch
dialog.visiblein the consuming component.