VueUse

Collection of Essential Vue Composition Utilities.

Components

OnClickOutside

vue
<script setup lang="ts">
const count = ref(0);
</script>

<template>
 <OnClickOutside
  @trigger="count++"
 >
  <div>
   Click Outside of Me
  </div>
  <div>
   Count: {{ count }}
  </div>
 </OnClickOutside>
</template>

UseActiveElement

vue
<template>
 <ClientOnly>
  <UseActiveElement v-slot="{ element }">
   Active element is {{ element?.tagName }}
  </UseActiveElement>
 </ClientOnly>
</template>

UseBattery

vue
<template>
 <UseBattery v-slot="{ charging }">
  Is Charging: {{ charging }}
 </UseBattery>
</template>

UseClipboard

vue
<template>
 <UseClipboard
  v-slot="{ copy, copied }"
  source="copy me"
 >
  <b-button
   color="button"
   @click="copy()"
  >
   {{ copied ? 'Copied' : 'Copy' }}
  </b-button>
 </UseClipboard>
</template>

UseDeviceMotion

vue
<template>
 <ClientOnly>
  <UseDeviceMotion v-slot="{ acceleration }">
   <JsonView :data="acceleration" />
   Acceleration: {{ acceleration.x }}, {{ acceleration.y }}, {{ acceleration.z }}, {{ acceleration.interval }}
  </UseDeviceMotion>
 </ClientOnly>
</template>

UseDeviceOrientation

vue
<template>
 <ClientOnly>
  <UseDeviceOrientation v-slot="{ alpha, beta, gamma }">
   Alpha: {{ alpha }}
   Beta: {{ beta }}
   Gamma: {{ gamma }}
  </UseDeviceOrientation>
 </ClientOnly>
</template>

UseDevicePixelRatio

vue
<template>
 <ClientOnly>
  <UseDevicePixelRatio v-slot="{ pixelRatio }">
   Pixel Ratio: {{ pixelRatio }}
  </UseDevicePixelRatio>
 </ClientOnly>
</template>

UseDeviceList

vue
<template>
 <ClientOnly>
  <UseDevicesList v-slot="{ videoInputs, audioInputs, audioOutputs }">
   <div>Cameras: {{ videoInputs }}</div>
   <div>Microphones: {{ audioInputs }}</div>
   <div>Speakers: {{ audioOutputs }}</div>
  </UseDevicesList>
 </ClientOnly>
</template>

UseDocumentVisibility

vue
<template>
 <ClientOnly>
  <UseDocumentVisibility v-slot="{ visibility }">
   Document Visibility: {{ visibility }}
  </UseDocumentVisibility>
 </ClientOnly>
</template>

UseDocumentVisibility

Fixed
vue
<script setup lang="ts">
const fixed = ref(false);
const style = computed(() => fixed.value ? 'position: fixed' : '');
</script>

<template>
 <b-input
  v-model="fixed"
  type="checkbox"
 />
 Fixed
 <UseDraggable
  v-slot="{ x, y }"
  :initial-value="{ x: 100, y: 100 }"
  :style="style"
 >
  Drag me! I am at {{ x }}, {{ y }}
 </UseDraggable>
</template>

UseElementBounding

vue
<template>
 <UseElementBounding
  v-slot="eb"
  style="display: inline-block; border: black solid 1px; padding:10px;"
 >
  <JsonView :data="eb" />
  <textarea
   readonly
   style="resize: both; min-width: 300px;"
  />
 </UseElementBounding>
</template>

UseElementSize

vue
<template>
 <UseElementSize v-slot="{ width, height }">
  Width: {{ width }} Height: {{ height }}
 </UseElementSize>
</template>

UseElementVisibility

vue
<template>
 <UseElementVisibility v-slot="{ isVisible }">
  Is Visible: {{ isVisible }}
 </UseElementVisibility>
</template>

UseEyeDropper

vue
<template>
 <ClientOnly>
  <UseEyeDropper
   v-slot="{ isSupported, sRGBHex, open }"
  >
   <b-button
    color="primary"
    :disabled="!isSupported"
    @click="open"
   >
    Eye Dropper
   </b-button>
   <div>
    sRGBHex: {{ sRGBHex }}
   </div>
  </UseEyeDropper>
 </ClientOnly>
</template>

UseFullscreen

vue
<template>
 <UseFullscreen v-slot="{ toggle }">
  <video
   src="/pexels/movie/3209211-uhd_3840_2160_25fps.mp4"
   class="image-fluid w-100"
   controls
  />
  <b-button
   color="primary"
   @click="toggle"
  >
   Go Fullscreen
  </b-button>
 </UseFullscreen>
</template>

UseGeolocation

vue
<template>
 <UseGeolocation v-slot="{ coords: { latitude, longitude } }">
  Latitude: {{ latitude }}
  Longitude: {{ longitude }}
 </UseGeolocation>
</template>

UseIdle

vue
<template>
 <UseIdle
  v-slot="{ idle }"
  :timeout="5 * 60 * 1000"
 >
  Is Idle: {{ idle }}
 </UseIdle>
</template>

UseMouseInElement

vue
<template>
 <UseMouseInElement v-slot="{ elementX, elementY, isOutside }">
  x: {{ elementX }}
  y: {{ elementY }}
  Is Outside: {{ isOutside }}
 </UseMouseInElement>
</template>

UseMousePressed

vue
<template>
 <UseMousePressed v-slot="{ pressed }">
  Is Pressed: {{ pressed }}
 </UseMousePressed>
</template>

UseNetwork

vue
<template>
 <ClientOnly>
  <UseNetwork v-slot="networkStatus">
   <JsonView :data="networkStatus" />
  </UseNetwork>
 </ClientOnly>
</template>

UseNow

vue
<template>
  <ClientOnly>
  <UseNow v-slot="{ now, pause, resume }">
   {{ now }}
   <b-button
    color="primary"
    @click="pause()"
   >
    Pause
   </b-button>
   <b-button
    color="primary"
    @click="resume()"
   >
    Resume
   </b-button>
  </UseNow>
 </ClientOnly>

</template>

UseObjectUrl

vue
<template>
  <ClientOnly>
  <UseNow v-slot="{ now, pause, resume }">
   {{ now }}
   <b-button
    color="primary"
    @click="pause()"
   >
    Pause
   </b-button>
   <b-button
    color="primary"
    @click="resume()"
   >
    Resume
   </b-button>
  </UseNow>
 </ClientOnly>

</template>

UseOffsetPagination

idname
vue
<script setup lang="ts">
interface User {
 id: number;
 name: string;
}
const database = ref([]) as Ref<User[]>;

for (let i = 0; i < 80; i++)
 database.value.push({ id: i, name: `user ${i}` });

function fetch(page: number, pageSize: number) {
 return new Promise<User[]>((resolve, reject) => {
  const start = (page - 1) * pageSize;
  const end = start + pageSize;
  setTimeout(() => {
   resolve(database.value.slice(start, end));
  }, 100);
 });
}

const data: Ref<User[]> = ref([]);

const page = ref(1);
const pageSize = ref(10);

fetchData({
 currentPage: page.value,
 currentPageSize: pageSize.value,
});

function fetchData({ currentPage, currentPageSize }: { currentPage: number; currentPageSize: number }) {
 fetch(currentPage, currentPageSize).then((responseData) => {
  data.value = responseData;
 });
}
</script>

<template>
 <UseOffsetPagination
  v-slot="{
   currentPage,
   currentPageSize,
   next,
   prev,
   pageCount,
   isFirstPage,
   isLastPage,
  }"
  :total="database.length"
  @page-change="fetchData"
  @page-size-change="fetchData"
 >
  <Grid
   :columns="2"
   display="inline-grid"
  >
   <div opacity="50">
    total:
   </div>
   <div>{{ database.length }}</div>
   <div opacity="50">
    pageCount:
   </div>
   <div>{{ pageCount }}</div>
   <div opacity="50">
    currentPageSize:
   </div>
   <div>{{ currentPageSize }}</div>
   <div opacity="50">
    currentPage:
   </div>
   <div>{{ currentPage }}</div>
   <div opacity="50">
    isFirstPage:
   </div>
   <div>{{ isFirstPage }}</div>
   <div opacity="50">
    isLastPage:
   </div>
   <div>{{ isLastPage }}</div>
  </Grid>
  <div>
   <b-button
    :disabled="isFirstPage"
    color="outline-primary"
    @click="prev"
   >
    prev
   </b-button>
   <b-button
    :disabled="isLastPage"
    color="outline-primary"
    @click="next"
   >
    next
   </b-button>
  </div>
 </UseOffsetPagination>
 <b-table
  small
  striped
 >
  <thead>
   <tr>
    <td>id</td>
    <td>name</td>
   </tr>
  </thead>
  <tbody>
   <tr
    v-for="d in data"
    :key="d.id"
   >
    <td>{{ d.id }}</td>
    <td>{{ d.name }}</td>
   </tr>
  </tbody>
 </b-table>
</template>

UseOnline

vue
<template>
 <ClientOnly>
  <UseOnline v-slot="{ isOnline }">
   Is Online: {{ isOnline }}
  </UseOnline>
 </ClientOnly>
</template>

UsePageLeave

vue
<template>
 <UsePageLeave v-slot="{ isLeft }">
  Has Left Page: {{ isLeft }}
 </UsePageLeave>
</template>

UsePointer

vue
<template>
 <ClientOnly>
  <UsePointer v-slot="pointer">
   <JsonView :data="pointer" />
  </UsePointer>
 </ClientOnly>
</template>

UsePointerLock

vue
<template>
 <ClientOnly>
  <UsePointerLock v-slot="pointerLock">
   <JsonView :data="pointerLock" />
  </UsePointerLock>
 </ClientOnly>
</template>

UseTimeAgo

vue
<template>
 <ClientOnly>
  <UseTimeAgo
   v-slot="{ timeAgo }"
   :time="new Date(2021, 0, 1)"
  >
   Time Ago: {{ timeAgo }}
  </UseTimeAgo>
 </ClientOnly>
</template>

UseTimestamp

vue
<template>
 <ClientOnly>
  <UseTimestamp v-slot="{ timestamp }">
   Current Time: {{ timestamp }}
  </UseTimestamp>
 </ClientOnly>
</template>

UseWindowFocus

vue
<template>
 <ClientOnly>
  <UseWindowFocus v-slot="{ focused }">
   Document Focus: {{ focused }}
  </UseWindowFocus>
 </ClientOnly>
</template>

UseWindowSize

vue
<template>
 <UseWindowSize v-slot="{ width, height }">
  <div>Width: {{ width }}</div>
  <div>Height: {{ height }}</div>
 </UseWindowSize>
</template>

Directives

OnLongPress

Long Pressed: false

vue
<script setup lang="ts">
const longPressedComponent = ref(false);

function onLongPressCallbackDirective(e: PointerEvent) {
 longPressedComponent.value = true;
}
function resetComponent() {
 longPressedComponent.value = false;
}
</script>

<template>
 <p>Long Pressed: {{ longPressedComponent }}</p>

 <b-button
  v-on-long-press.prevent="onLongPressCallbackDirective"
  mergin="l-2"
  color="primary"
  class="ml-2"
 >
  Press long
 </b-button>

 <b-button
  mergin="l-2"
  color="secondary"
  class="ml-2"
  @click="resetComponent"
 >
  Reset
 </b-button>
</template>