Skip to content

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.visible in the consuming component.