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 onlyshow() 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.