npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

directix

v1.7.0

Published

A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3

Downloads

1,401

Readme

Directix

npm version npm downloads GitHub license

English | 中文文档

A comprehensive, easy-to-use, and high-performance Vue custom directives library supporting both Vue 2 and Vue 3.

Features

  • 🎯 Comprehensive - 57 commonly used directives and 57 composables
  • 🔄 Vue 2/3 Compatible - Single codebase supports both Vue 2 and Vue 3
  • 📦 Tree-shakable - Import only what you need
  • 🔒 TypeScript - Full TypeScript support with type definitions
  • 🚀 SSR Friendly - Multiple directives support SSR out of the box
  • 📦 Multiple Formats - ESM, CJS, and IIFE (CDN) formats available
  • Zero Dependencies - Lightweight with minimal bundle size
  • 🎨 Composables - Every directive has a corresponding composable for Composition API
  • 🔧 Utility Exports - Export configurePermission, getPermissionConfig and other utilities for advanced usage

Online Demo

Try it online with StackBlitz or CodeSandbox:

| Demo | StackBlitz | CodeSandbox | |------|------------|-------------| | Vue 3 | Open in StackBlitz | Open in CodeSandbox | | Vue 2 | Open in StackBlitz | Open in CodeSandbox |

Playground

Try the interactive Playground to configure directives and generate code:

  • 57+ Directives - Full coverage of all Directix directives
  • Vue 2 & Vue 3 - Generate code for either version
  • Composables - Generate composable API code
  • TypeScript Ready - Full type definitions included
  • Monaco Editor - Full-featured code editor with syntax highlighting
  • Live Preview - See directive effects in real-time

Each directive documentation page also includes a code generator for quick code snippets.

Installation

# npm
npm install directix

# yarn
yarn add directix

# pnpm
pnpm add directix

Vue 2 Support

For Vue 2.0-2.6, you need to install @vue/composition-api:

npm install @vue/composition-api

Vue 2.7+ has built-in Composition API support, so no additional dependencies are needed.

CDN

You can also use Directix via CDN:

<!-- Vue 3 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://unpkg.com/directix/dist/index.iife.min.js"></script>

<!-- Vue 2.7+ -->
<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/directix/dist/index.iife.min.js"></script>

The CDN build works seamlessly with both Vue 2 and Vue 3.

Requirements

  • Vue 2.0+ or Vue 3.0+
  • Node.js 12.20+ (for build tools)
  • For Vue 2.0-2.6: @vue/composition-api is required

Quick Start

Global Registration

// Vue 3
import { createApp } from 'vue'
import Directix from 'directix'

const app = createApp(App)
app.use(Directix)

// Or register specific directives only
app.use(Directix, {
  directives: ['click-outside', 'copy', 'debounce']
})
// Vue 2
import Vue from 'vue'
import Directix from 'directix'

Vue.use(Directix)

On-Demand Import

import { vClickOutside, vCopy, vDebounce } from 'directix'

// Vue 3
app.directive('click-outside', vClickOutside)
app.directive('copy', vCopy)

// Vue 2
Vue.directive('click-outside', vClickOutside)

Using Composables

Every directive has a corresponding composable for use with the Composition API:

import { useClickOutside, useCopy, useDebounce } from 'directix'

// In setup() or <script setup>
const { copy, copied } = useCopy({ source: textRef })
const { isHovering, bind } = useHover({ onEnter: handleEnter })
const { run: debouncedSearch } = useDebounce({ handler: search, wait: 500 })

See the Composables section below for all available composables.

Nuxt Integration

Directix provides a Nuxt module for seamless integration with Nuxt 3 applications.

Installation

The Nuxt module is included in the main package. Simply add it to your nuxt.config.ts:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['directix/nuxt'],
  
  directix: {
    // Enable/disable the module (default: true)
    enabled: true,
    
    // Only include specific directives (optional)
    include: ['v-click-outside', 'v-copy', 'v-debounce'],
    
    // Or exclude specific directives (optional)
    exclude: ['v-ripple'],
    
    // Default options for directives (optional)
    directiveOptions: {
      'v-permission': {
        config: {
          getPermissions: () => ['read', 'write']
        }
      }
    },
    
    // Auto-import composables (default: true)
    autoImportComposables: true
  }
})

Usage in Nuxt

Directives are automatically registered and composables are auto-imported:

<template>
  <div v-click-outside="handleClose">
    <button v-copy="text">Copy</button>
  </div>
</template>

<script setup>
// Composables are auto-imported, no need to import manually
const { copy, copied } = useCopy({ source: text })
const { isHovering } = useHover({ onEnter: handleEnter })
</script>

SSR Compatibility

Directives that are not SSR-compatible will only run on the client side. The Nuxt module handles this automatically.

Available Directives

Event Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-click-outside | Detect clicks outside an element | ❌ | | v-click-delay | Delay click execution to prevent double clicks | ✅ | | v-debounce | Debounce event handlers | ✅ | | v-throttle | Throttle event handlers | ✅ | | v-long-press | Detect long press events | ❌ | | v-hover | Hover state detection | ❌ | | v-hotkey | Keyboard shortcut binding | ✅ | | v-touch | Touch gesture detection (swipe, pinch, rotate) | ❌ | | v-swipe | Swipe gesture detection with mouse support | ❌ |

Form Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-copy | Copy text to clipboard | ❌ | | v-focus | Auto focus an element | ✅ | | v-mask | Input masking | ❌ | | v-trim | Trim input whitespace | ✅ | | v-money | Currency format input | ❌ | | v-number | Number format input | ❌ | | v-ellipsis | Text ellipsis overflow | ✅ |

Format Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-uppercase | Convert text to uppercase | ✅ | | v-lowercase | Convert text to lowercase | ✅ | | v-capitalcase | Capitalize first letter | ✅ | | v-truncate | Truncate text with ellipsis | ✅ |

Visibility Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-lazy | Lazy load images | ❌ | | v-intersect | Detect element intersection | ❌ | | v-visible | Control element visibility | ✅ | | v-loading | Show loading overlay | ✅ |

Scroll Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-scroll | Scroll event handling | ❌ | | v-infinite-scroll | Infinite scrolling | ❌ | | v-sticky | Sticky positioning | ❌ | | v-pull-refresh | Pull to refresh functionality | ❌ | | v-virtual-list | Virtual list for large datasets | ❌ |

Security Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-permission | Permission-based element control | ✅ | | v-sanitize | Sanitize HTML content | ✅ |

Effect Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-ripple | Material design ripple effect | ❌ | | v-draggable | Make elements draggable | ❌ |

Observer Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-resize | Element resize observer | ❌ | | v-mutation | DOM mutation observer | ❌ |

UI Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-tooltip | Tooltip component | ❌ | | v-image-preview | Image preview with zoom | ❌ | | v-countdown | Countdown timer display | ✅ | | v-print | Print element content | ❌ | | v-watermark | Watermark overlay | ✅ | | v-skeleton | Skeleton loading placeholder | ✅ | | v-progress | Progress bar animation | ❌ | | v-counter | Animated number counter | ✅ |

Gesture Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-pan | Pan/drag gesture | ❌ | | v-pinch | Pinch/zoom gesture | ❌ | | v-rotate-gesture | Rotation gesture | ❌ |

Visual Effect Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-blur | Background blur overlay | ❌ | | v-fade | Fade in/out transition | ✅ | | v-parallax | Parallax scrolling effect | ❌ | | v-lottie | Lottie animation player | ❌ | | v-typewriter | Typewriter animation | ✅ | | v-click-wave | Click wave effect | ❌ |

Data Directives

| Directive | Description | SSR | |-----------|-------------|-----| | v-export | Export data (CSV/JSON/HTML) | ❌ | | v-highlight | Keyword highlighting | ✅ | | v-emoji | Emoji input filter | ❌ | | v-context-menu | Right-click context menu | ❌ | | v-fullscreen | Fullscreen toggle | ❌ |

✅ = SSR compatible | ❌ = Not SSR compatible

Composables

Every directive has a corresponding composable function for use with the Composition API. All composables are exported from directix:

Event Composables

| Composable | Description | |------------|-------------| | useClickOutside | Detect clicks outside an element | | useClickDelay | Delay click execution | | useDebounce | Debounce function calls | | useThrottle | Throttle function calls | | useLongPress | Detect long press gestures | | useHover | Track hover state | | useHotkey | Handle keyboard shortcuts | | useTouch | Detect touch gestures | | useSwipe | Detect swipe gestures |

Form Composables

| Composable | Description | |------------|-------------| | useCopy | Copy text to clipboard | | useFocus | Manage element focus | | useMask | Input masking | | useTrim | Trim input whitespace | | useMoney | Currency formatting | | useNumber | Number formatting | | useEllipsis | Text ellipsis overflow |

Format Composables

| Composable | Description | |------------|-------------| | useUppercase | Transform to uppercase | | useLowercase | Transform to lowercase | | useCapitalcase | Capitalize text | | useTruncate | Truncate text |

Visibility Composables

| Composable | Description | |------------|-------------| | useLazy | Lazy load images | | useIntersect | Detect element intersection | | useVisible | Control element visibility | | useLoading | Show loading overlay |

Scroll Composables

| Composable | Description | |------------|-------------| | useScroll | Track scroll position | | useInfiniteScroll | Infinite scrolling | | useSticky | Sticky positioning | | usePullRefresh | Pull to refresh | | useVirtualList | Virtual list for large datasets |

Other Composables

| Composable | Description | |------------|-------------| | usePermission | Permission checking | | useSanitize | Sanitize HTML content | | useRipple | Material design ripple effect | | useDraggable | Make elements draggable | | useResize | Element resize observer | | useMutation | DOM mutation observer | | useTooltip | Tooltip control | | useImagePreview | Image preview with zoom | | useCountdown | Countdown timer | | usePrint | Print content | | useWatermark | Watermark overlay | | useSkeleton | Skeleton loading state | | useProgress | Progress bar control | | useCounter | Animated number counter | | usePan | Pan gesture detection | | usePinch | Pinch gesture detection | | useRotateGesture | Rotation gesture detection | | useBlur | Blur overlay control | | useFade | Fade transition control | | useParallax | Parallax scrolling | | useLottie | Lottie animation control | | useTypewriter | Typewriter effect | | useExport | Data export utilities | | useHighlight | Keyword highlighting | | useEmoji | Emoji filtering | | useContextMenu | Context menu control | | useFullscreen | Fullscreen mode control | | useClickWave | Click wave effect |

Composable Usage Example

<script setup>
import { ref } from 'vue'
import { useCopy, useHover, useDebounce } from 'directix'

// useCopy
const text = ref('Hello World')
const { copy, copied } = useCopy({ source: text })

// useHover
const buttonRef = ref()
const { isHovering, bind } = useHover({
  onEnter: () => console.log('Entered'),
  onLeave: () => console.log('Left')
})

// useDebounce
const { run: debouncedSearch } = useDebounce({
  handler: (query) => fetchResults(query),
  wait: 500
})
</script>

<template>
  <button @click="copy()">
    {{ copied ? 'Copied!' : 'Copy' }}
  </button>

  <button ref="buttonRef" :class="{ active: isHovering }">
    Hover me
  </button>
</template>

Usage Examples

v-click-outside

Detect clicks outside an element, useful for closing dropdowns, modals, etc.

<template>
  <div v-click-outside="closeDropdown">
    <button @click="show = !show">Toggle</button>
    <div v-if="show">Dropdown content</div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useClickOutside } from 'directix'

const show = ref(false)

function closeDropdown() {
  show.value = false
}

// Composable usage
const containerRef = ref()
useClickOutside(containerRef, () => {
  show.value = false
})
</script>

v-copy

Copy text to clipboard with a simple directive.

<template>
  <!-- Simple usage -->
  <button v-copy="textToCopy">Copy to clipboard</button>

  <!-- With callbacks -->
  <button v-copy="{ value: text, onSuccess: handleSuccess, onError: handleError }">
    Copy with callback
  </button>
</template>

<script setup>
import { ref } from 'vue'
import { useCopy } from 'directix'

const textToCopy = 'Hello, World!'

function handleSuccess(text) {
  console.log('Copied:', text)
}

function handleError(error) {
  console.error('Copy failed:', error)
}

// Composable usage
const sourceText = ref('Hello World')
const { copy, copied } = useCopy({ source: sourceText })
</script>

v-debounce

Debounce event handlers to limit execution frequency.

<template>
  <!-- Default: 300ms -->
  <input v-debounce="handleInput" />

  <!-- Custom wait time with modifier -->
  <input v-debounce:500ms="handleInput" />

  <!-- With options object -->
  <input v-debounce="{ handler: handleInput, wait: 500, leading: true }" />
</template>

<script setup>
import { useDebounce } from 'directix'

function handleInput(event) {
  console.log('Debounced input:', event.target.value)
}

// Composable usage
const { run: debouncedSearch, cancel } = useDebounce({
  handler: (query) => fetchResults(query),
  wait: 500
})
</script>

v-throttle

Throttle event handlers to limit execution frequency.

<template>
  <!-- Default: 300ms -->
  <button v-throttle="handleClick">Throttled click</button>

  <!-- Custom wait time with modifier -->
  <button v-throttle:1s="handleClick">1 second throttle</button>

  <!-- With options object -->
  <button v-throttle="{ handler: handleClick, wait: 1000, leading: true, trailing: false }">
    Throttle with options
  </button>
</template>

<script setup>
import { useThrottle } from 'directix'

function handleClick() {
  console.log('Throttled click')
}

// Composable usage
const { run: throttledScroll, cancel } = useThrottle({
  handler: (position) => updatePosition(position),
  wait: 100
})
</script>

v-focus

Auto focus an element when mounted.

<template>
  <!-- Simple usage -->
  <input v-focus />

  <!-- With options -->
  <input v-focus="{ focus: true, refocus: true }" />
</template>

<script setup>
import { useFocus } from 'directix'

// Composable usage
const { focus, blur, hasFocus } = useFocus()
</script>

v-permission

Control element visibility based on user permissions.

<template>
  <!-- Simple permission check -->
  <button v-permission="'admin'">Admin Only</button>

  <!-- Multiple permissions (OR logic) -->
  <button v-permission="['admin', 'editor']">Admin or Editor</button>

  <!-- AND logic -->
  <button v-permission="{ value: ['read', 'write'], mode: 'every' }">
    Requires both permissions
  </button>

  <!-- Disable instead of remove -->
  <button v-permission="{ value: 'admin', action: 'disable' }">
    Disabled for non-admin
  </button>
</template>

<script setup>
import { configurePermission, usePermission } from 'directix'

configurePermission({
  getPermissions: () => ['read', 'write'],
  getRoles: () => ['editor'],
  roleMap: {
    admin: ['*'],
    editor: ['read', 'write', 'edit']
  }
})

// Composable usage
const { hasPermission, hasAnyPermission, hasAllPermissions } = usePermission()
const canEdit = hasPermission('edit')
</script>

v-lazy

Lazy load images when they enter the viewport.

<template>
  <!-- Simple usage -->
  <img v-lazy="imageUrl" />

  <!-- With placeholder and error image -->
  <img v-lazy="{ src: imageUrl, placeholder: '/placeholder.png', error: '/error.png' }" />
</template>

<script setup>
import { useLazy } from 'directix'

// Composable usage
const { load, state, loaded } = useLazy({
  src: 'image.jpg',
  preload: 100
})
</script>

v-mask

Input masking for formatted input.

<template>
  <!-- Phone number -->
  <input v-mask="'(###) ###-####'" placeholder="Phone" />

  <!-- Date -->
  <input v-mask="'##/##/####'" placeholder="MM/DD/YYYY" />

  <!-- SSN -->
  <input v-mask="{ mask: '###-##-####', placeholder: '_' }" placeholder="SSN" />
</template>

<script setup>
import { useMask } from 'directix'

// Composable usage
const { maskedValue, unmaskedValue, update } = useMask({
  mask: '(###) ###-####',
  value: '1234567890'
})
</script>

v-loading

Show loading overlay on elements.

<template>
  <!-- Simple usage -->
  <div v-loading="isLoading">Content</div>

  <!-- With options -->
  <div v-loading="{ value: isLoading, text: 'Loading...', lock: true }">
    Content with locked scroll
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useLoading } from 'directix'

const isLoading = ref(true)

// Composable usage
const { show, hide, setText } = useLoading({
  text: 'Loading...',
  lock: true
})
</script>

v-sanitize

Sanitize HTML content to prevent XSS attacks.

<template>
  <!-- Simple usage -->
  <div v-sanitize="userContent"></div>

  <!-- With custom allowed tags -->
  <div v-sanitize="{ html: userContent, allowedTags: ['b', 'i', 'u'] }"></div>
</template>

<script setup>
import { useSanitize } from 'directix'

// Composable usage
const { sanitize, setAllowedTags } = useSanitize({
  allowedTags: ['b', 'i', 'u', 'a']
})
const cleanHtml = sanitize(dirtyHtml)
</script>

v-tooltip

Display tooltips on hover or click.

<template>
  <!-- Simple usage -->
  <button v-tooltip="'Tooltip content'">Hover me</button>

  <!-- With options -->
  <button v-tooltip="{ content: 'Tooltip', placement: 'bottom', trigger: 'click' }">
    Click me
  </button>
</template>

<script setup>
import { useTooltip } from 'directix'

// Composable usage
const { show, hide, updateContent, updatePosition } = useTooltip({
  content: 'Tooltip content',
  placement: 'top'
})
</script>

v-image-preview

Preview images with zoom and gesture support.

<template>
  <!-- Simple usage -->
  <img v-image-preview src="thumbnail.jpg" data-preview="full.jpg" />

  <!-- With options -->
  <img v-image-preview="{ src: 'thumbnail.jpg', previewSrc: 'full.jpg', enablePinchZoom: true }" />
</template>

<script setup>
import { useImagePreview } from 'directix'

// Composable usage
const { open, close, zoom, rotate } = useImagePreview({
  enablePinchZoom: true
})
</script>

v-draggable

Make elements draggable.

<template>
  <!-- Simple usage -->
  <div v-draggable>Drag me</div>

  <!-- With constraints -->
  <div v-draggable="{ axis: 'x', bounds: 'parent' }">Horizontal drag only</div>
</template>

<script setup>
import { useDraggable } from 'directix'

// Composable usage
const { position, isDragging, reset } = useDraggable({
  axis: 'x',
  bounds: 'parent'
})
</script>

v-uppercase / v-lowercase / v-capitalcase

Transform text case.

<template>
  <input v-uppercase placeholder="Auto uppercase" />
  <input v-lowercase placeholder="Auto lowercase" />
  <input v-capitalcase placeholder="Capitalize first letter" />
</template>

<script setup>
import { useUppercase, useLowercase, useCapitalcase } from 'directix'

// Composable usage
const { transform: toUppercase } = useUppercase()
const { transform: toLowercase } = useLowercase()
const { transform: toCapitalcase } = useCapitalcase()
</script>

v-truncate

Truncate text with ellipsis.

<template>
  <!-- Simple usage -->
  <p v-truncate="50">Long text here...</p>

  <!-- With options -->
  <p v-truncate="{ length: 100, suffix: '...', position: 'end' }">Long text...</p>
</template>

<script setup>
import { useTruncate } from 'directix'

// Composable usage
const { truncate } = useTruncate({ length: 100, suffix: '...' })
const shortText = truncate(longText)
</script>

v-touch

Detect touch gestures.

<template>
  <div v-touch="{ onSwipe: handleSwipe, onPinch: handlePinch }">
    Swipe or pinch here
  </div>
</template>

<script setup>
import { useTouch } from 'directix'

function handleSwipe(direction) {
  console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'
}

function handlePinch(scale) {
  console.log('Pinched:', scale)
}

// Composable usage
const { onSwipe, onPinch, onRotate } = useTouch({
  onSwipe: handleSwipe
})
</script>

v-trim

Trim input whitespace.

<template>
  <!-- Trim on blur (default) -->
  <input v-trim />

  <!-- Trim on input -->
  <input v-trim="{ position: 'both', event: 'input' }" />
</template>

<script setup>
import { useTrim } from 'directix'

// Composable usage
const { trim, trimLeft, trimRight } = useTrim({ position: 'both' })
</script>

v-money

Currency format input.

<template>
  <input v-money="{ prefix: '$', precision: 2 }" placeholder="Enter amount" />
</template>

<script setup>
import { useMoney } from 'directix'

// Composable usage
const { format, parse } = useMoney({ prefix: '$', precision: 2 })
const formatted = format(1234.56) // "$1,234.56"
</script>

v-number

Number format input.

<template>
  <input v-number="{ precision: 2, min: 0, max: 100 }" placeholder="Enter number" />
</template>

<script setup>
import { useNumber } from 'directix'

// Composable usage
const { format, parse } = useNumber({ precision: 2, min: 0, max: 100 })
</script>

v-click-delay

Delay click execution to prevent double clicks.

<template>
  <!-- Default: 300ms delay -->
  <button v-click-delay="handleClick">Click me</button>

  <!-- Custom delay time -->
  <button v-click-delay="{ handler: handleClick, delay: 500 }">500ms delay</button>
</template>

<script setup>
import { useClickDelay } from 'directix'

function handleClick() {
  console.log('Clicked (delayed)')
}

// Composable usage
const { run: delayedClick, cancel } = useClickDelay({
  handler: handleClick,
  delay: 300
})
</script>

v-countdown

Countdown timer display.

<template>
  <!-- Simple usage -->
  <span v-countdown="{ time: 60 }"></span>

  <!-- With callbacks -->
  <span v-countdown="{ time: 60, onTick: handleTick, onComplete: handleComplete }"></span>

  <!-- Custom format -->
  <span v-countdown="{ time: 3600, format: 'mm:ss' }"></span>
</template>

<script setup>
import { useCountdown } from 'directix'

function handleTick(remaining) {
  console.log('Remaining:', remaining)
}

function handleComplete() {
  console.log('Countdown complete!')
}

// Composable usage
const { start, pause, reset, remaining } = useCountdown({
  time: 60,
  onTick: handleTick,
  onComplete: handleComplete
})
</script>

v-ellipsis

Text ellipsis overflow with tooltip.

<template>
  <!-- Simple usage -->
  <div v-ellipsis style="width: 200px;">Long text that will be truncated</div>

  <!-- With custom lines -->
  <div v-ellipsis="{ lines: 2 }">Multi-line text with ellipsis</div>
</template>

<script setup>
import { useEllipsis } from 'directix'

// Composable usage
const { isEllipsisActive, checkEllipsis } = useEllipsis({ lines: 1 })
</script>

v-hotkey

Keyboard shortcut binding.

<template>
  <!-- Simple usage -->
  <div v-hotkey="{ 'ctrl+s': handleSave, 'ctrl+c': handleCopy }">
    Press Ctrl+S to save
  </div>

  <!-- With modifiers -->
  <input v-hotkey="{ 'enter': submit, 'escape': cancel }" />
</template>

<script setup>
import { useHotkey } from 'directix'

function handleSave() {
  console.log('Saving...')
}

function handleCopy() {
  console.log('Copying...')
}

// Composable usage
const { bind, unbind, unbindAll } = useHotkey({
  'ctrl+s': handleSave
})
</script>

v-print

Print element content.

<template>
  <!-- Simple usage -->
  <button v-print="printRef">Print</button>
  <div ref="printRef">Content to print</div>

  <!-- Print self -->
  <div v-print="{ self: true }">Click to print this content</div>
</template>

<script setup>
import { ref } from 'vue'
import { usePrint } from 'directix'

const printRef = ref()

// Composable usage
const { print, printElement } = usePrint({
  onBefore: () => console.log('Printing...'),
  onComplete: () => console.log('Printed!')
})
</script>

v-pull-refresh

Pull to refresh functionality.

<template>
  <div v-pull-refresh="handleRefresh" style="height: 400px; overflow: auto;">
    Pull down to refresh
  </div>

  <!-- With options -->
  <div v-pull-refresh="{ handler: handleRefresh, threshold: 80, disabled: false }">
    Content
  </div>
</template>

<script setup>
import { usePullRefresh } from 'directix'

async function handleRefresh() {
  // Fetch new data
  await fetchData()
}

// Composable usage
const { isLoading, disable, enable } = usePullRefresh({
  handler: handleRefresh
})
</script>

v-swipe

Swipe gesture detection with mouse support.

<template>
  <div v-swipe="handleSwipe" style="height: 200px;">
    Swipe in any direction
  </div>

  <!-- With options -->
  <div v-swipe="{ onSwipe: handleSwipe, threshold: 50, enableMouse: true }">
    Swipe or drag with mouse
  </div>
</template>

<script setup>
import { useSwipe } from 'directix'

function handleSwipe(direction) {
  console.log('Swiped:', direction) // 'left', 'right', 'up', 'down'
}

// Composable usage
const { direction, lengthX, lengthY } = useSwipe({
  onSwipe: handleSwipe,
  threshold: 50
})
</script>

v-virtual-list

Virtual list for rendering large datasets efficiently.

<template>
  <div v-virtual-list="{ items: list, itemSize: 50 }" style="height: 500px;">
    <template #default="{ item, index }">
      <div :key="index">{{ item.name }}</div>
    </template>
  </div>
</template>

<script setup>
const list = Array.from({ length: 10000 }, (_, i) => ({ id: i, name: `Item ${i}` }))

import { useVirtualList } from 'directix'

// Composable usage
const { list, containerProps, wrapperProps, scrollTo } = useVirtualList(
  largeList,
  { itemHeight: 50 }
)
</script>

v-watermark

Watermark overlay.

<template>
  <!-- Simple usage -->
  <div v-watermark="'Confidential'" style="width: 100%; height: 400px;">
    Protected content
  </div>

  <!-- With options -->
  <div v-watermark="{ content: 'Draft', fontSize: 16, color: '#ccc', rotate: -20 }">
    Content with watermark
  </div>
</template>

<script setup>
import { useWatermark } from 'directix'

// Composable usage
const { show, hide, update } = useWatermark({
  content: 'Confidential',
  fontSize: 16,
  color: '#ccc'
})
</script>

v-blur

Background blur overlay effect.

<template>
  <!-- Simple blur -->
  <div v-blur="isBlurred">Content behind blur</div>

  <!-- With radius -->
  <div v-blur="15">Blur with 15px radius</div>

  <!-- With options -->
  <div v-blur="{
    visible: isBlurred,
    radius: 20,
    overlayColor: 'rgba(255, 255, 255, 0.3)',
    lockScroll: true
  }">
    Content
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useBlur } from 'directix'

const isBlurred = ref(false)

// Composable usage
const { show, hide, toggle } = useBlur({
  radius: 10,
  overlayColor: 'rgba(0, 0, 0, 0.5)'
})
</script>

v-fade

Fade in/out transition effect.

<template>
  <!-- Toggle visibility with fade -->
  <div v-fade="isVisible">Fade content</div>

  <!-- Fade in only -->
  <div v-fade="'in'">Fade in</div>

  <!-- With options -->
  <div v-fade="{
    visible: isVisible,
    duration: 500,
    easing: 'ease-in-out',
    onComplete: () => console.log('Fade complete')
  }">
    Content
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useFade } from 'directix'

const isVisible = ref(true)

// Composable usage
const { fadeIn, fadeOut, toggle } = useFade({
  duration: 300,
  easing: 'ease'
})
</script>

v-parallax

Parallax scrolling effect.

<template>
  <!-- Simple parallax -->
  <div v-parallax>Parallax content</div>

  <!-- With speed factor -->
  <div v-parallax="0.3">Slower parallax</div>

  <!-- With options -->
  <div v-parallax="{
    speed: 0.5,
    reverse: true,
    mobileBreakpoint: 768
  }">
    Reverse parallax, disabled on mobile
  </div>
</template>

<script setup>
import { useParallax } from 'directix'

// Composable usage
const { offset, progress, enabled } = useParallax({
  speed: 0.5,
  reverse: false
})
</script>

v-lottie

Lottie animation player.

<template>
  <!-- With URL -->
  <div v-lottie="'https://assets.example.com/animation.json'"></div>

  <!-- With animation data -->
  <div v-lottie="animationData"></div>

  <!-- With options -->
  <div v-lottie="{
    animationData: animationData,
    autoplay: true,
    loop: true,
    speed: 1.5,
    onComplete: () => console.log('Done')
  }"></div>
</template>

<script setup>
import animationData from './animation.json'
import { useLottie } from 'directix'

// Composable usage
const { play, pause, stop, setSpeed, setDirection } = useLottie({
  animationData,
  autoplay: true,
  loop: true
})
</script>

v-typewriter

Typewriter animation effect.

<template>
  <!-- Simple usage -->
  <span v-typewriter="'Hello, World!'"></span>

  <!-- With options -->
  <span v-typewriter="{
    text: 'Typing animation',
    speed: 100,
    cursor: '_',
    onComplete: () => console.log('Done!')
  }"></span>

  <!-- Loop mode -->
  <span v-typewriter="{
    text: 'Loop animation',
    loop: true,
    deleteDelay: 1000
  }"></span>
</template>

<script setup>
import { useTypewriter } from 'directix'

// Composable usage
const { start, stop, pause, resume } = useTypewriter({
  text: 'Hello World',
  speed: 50,
  loop: false
})
</script>

v-export

Export data (CSV/JSON/HTML/TXT).

<template>
  <button v-export="exportData">Export CSV</button>

  <button v-export="{ data: tableData, format: 'json', filename: 'my-data' }">
    Export JSON
  </button>

  <button v-export="{
    data: tableData,
    format: 'csv',
    columns: ['name', 'email'],
    headers: { name: 'Name', email: 'Email Address' }
  }">
    Export with custom columns
  </button>
</template>

<script setup>
const tableData = [
  { name: 'John', email: '[email protected]', age: 30 },
  { name: 'Jane', email: '[email protected]', age: 25 }
]

import { useExport } from 'directix'

// Composable usage
const { exportCSV, exportJSON, exportHTML } = useExport()
</script>

v-highlight

Keyword highlighting.

<template>
  <p v-highlight="'important'">This is an important message.</p>

  <p v-highlight="['Vue', 'React']">Vue and React are popular frameworks.</p>

  <p v-highlight="{
    keywords: 'highlight',
    className: 'my-highlight',
    style: 'background: yellow; color: black;',
    caseSensitive: true
  }">
    This will highlight the word.
  </p>
</template>

<script setup>
import { useHighlight } from 'directix'

// Composable usage
const { highlight, clear } = useHighlight({
  keywords: ['important', 'key'],
  className: 'highlight'
})
</script>

v-emoji

Emoji input filter.

<template>
  <!-- Strip all emojis -->
  <input v-emoji type="text" />

  <!-- Strip emojis with replacement -->
  <input v-emoji="{ strip: true, replacement: '*' }" type="text" />

  <!-- Allow specific emojis -->
  <input v-emoji="{ allowList: ['😊', '👍'] }" type="text" />

  <!-- Block specific emojis -->
  <input v-emoji="{ blockList: ['🚫', '❌'] }" type="text" />
</template>

<script setup>
import { useEmoji } from 'directix'

// Composable usage
const { stripEmojis, containsEmoji } = useEmoji({
  strip: true,
  allowList: ['😊', '👍']
})
</script>

v-context-menu

Right-click context menu.

<template>
  <div v-context-menu="menuItems">Right click here</div>
  <div v-context-menu="{ items: menuItems, width: 200 }">Custom width</div>
</template>

<script setup>
import { useContextMenu } from 'directix'

const menuItems = [
  { label: 'Copy', handler: () => console.log('Copy') },
  { label: 'Paste', handler: () => console.log('Paste') },
  { divider: true, label: '' },
  { label: 'Delete', handler: () => console.log('Delete') }
]

// Composable usage
const { show, hide, setItems } = useContextMenu({
  items: menuItems
})
</script>

v-fullscreen

Fullscreen toggle.

<template>
  <div v-fullscreen>
    Content to show in fullscreen
    <button @click="$el.toggleFullscreen()">Toggle</button>
  </div>

  <div v-fullscreen="{ fullscreenClass: 'my-fullscreen' }">
    Custom fullscreen class
  </div>
</template>

<script setup>
import { useFullscreen } from 'directix'

// Composable usage
const { isFullscreen, enter, exit, toggle } = useFullscreen({
  onEnter: () => console.log('Entered fullscreen'),
  onExit: () => console.log('Exited fullscreen')
})
</script>

v-skeleton

Skeleton loading placeholder.

<template>
  <!-- Basic usage -->
  <div v-skeleton="isLoading">Content here</div>

  <!-- With options -->
  <div v-skeleton="{ loading: isLoading, animation: 'pulse', width: 200, height: 20 }">
    Content here
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useSkeleton } from 'directix'

const isLoading = ref(true)

// Composable usage
const { show, hide, update } = useSkeleton({
  animation: 'wave',
  color: '#e8e8e8'
})
</script>

v-progress

Progress bar animation.

<template>
  <div v-progress="50">Progress at 50%</div>

  <div v-progress="{
    value: progressValue,
    color: '#42b883',
    height: 8,
    showText: true
  }">
    Content
  </div>

  <div v-progress="{ indeterminate: true }">
    Loading...
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useProgress } from 'directix'

const progressValue = ref(50)

// Composable usage
const { setProgress, start, finish, fail } = useProgress({
  color: '#42b883',
  height: 4
})
</script>

v-counter

Animated number counter.

<template>
  <span v-counter="1000">0</span>

  <span v-counter="{
    value: 10000,
    duration: 3000,
    decimals: 2,
    useGrouping: true
  }">0</span>

  <span v-counter="{
    value: targetValue,
    formatter: (v) => '$' + v.toFixed(2)
  }">0</span>
</template>

<script setup>
import { ref } from 'vue'
import { useCounter } from 'directix'

const targetValue = ref(1000)

// Composable usage
const { start, pause, reset, update } = useCounter({
  startValue: 0,
  endValue: 1000,
  duration: 2000,
  formatter: (v) => `$${v.toFixed(2)}`
})
</script>

v-click-wave

Click wave effect.

<template>
  <button v-click-wave>Click me</button>
  <button v-click-wave="'rgba(255, 255, 255, 0.3)'">Custom color</button>
  <button v-click-wave="{ color: 'red', duration: 400 }">Custom options</button>
</template>

<script setup>
import { ref } from 'vue'
import { useClickWave } from 'directix'

// Composable usage
const buttonRef = ref(null)
const { bind, trigger } = useClickWave({
  color: 'currentColor',
  duration: 500
})

// Bind to element on mount
onMounted(() => bind(buttonRef.value))
</script>

v-pan

Pan/drag gesture.

<template>
  <div v-pan="handlePan">Swipe me</div>

  <div v-pan="{
    onPan: handlePan,
    direction: 'horizontal',
    threshold: 20
  }">
    Horizontal only
  </div>
</template>

<script setup>
import { usePan } from 'directix'

function handlePan(e) {
  console.log('Direction:', e.direction)
  console.log('Distance:', e.distance)
}

// Composable usage
const { isPanning, deltaX, deltaY } = usePan({
  onPan: handlePan,
  direction: 'horizontal'
})
</script>

v-pinch

Pinch/zoom gesture.

<template>
  <div v-pinch="handlePinch">Pinch to zoom</div>

  <div v-pinch="{
    onPinch: handlePinch,
    enableTransform: true,
    minScale: 0.5,
    maxScale: 3
  }">
    Pinch to scale
  </div>
</template>

<script setup>
import { usePinch } from 'directix'

function handlePinch(e) {
  console.log('Scale:', e.scale)
  console.log('Center:', e.centerX, e.centerY)
}

// Composable usage
const { scale, isPinching } = usePinch({
  onPinch: handlePinch,
  minScale: 0.5,
  maxScale: 3
})
</script>

v-rotate-gesture

Rotation gesture.

<template>
  <div v-rotate-gesture="handleRotate">Rotate with two fingers</div>

  <div v-rotate-gesture="{
    onRotate: handleRotate,
    enableTransform: true
  }">
    Rotate with transform
  </div>
</template>

<script setup>
import { useRotateGesture } from 'directix'

function handleRotate(e) {
  console.log('Rotation:', e.rotation)
  console.log('Angle:', e.angle)
}

// Composable usage
const { angle, isRotating } = useRotateGesture({
  onRotate: handleRotate,
  enableTransform: true
})
</script>

API Reference

DirectiveInstallOptions

interface DirectiveInstallOptions {
  /** Register specific directives only */
  directives?: string[]
  /** Register all directives (default: true) */
  all?: boolean
  /** Global configuration for directives */
  config?: Record<string, any>
}

Directive Options

Each directive accepts different options. See the documentation for detailed API.

Roadmap

v1.7.0 (2026-04-15) - Visual Configuration Tool ✅

  • Online Playground - Live editing environment with Vue 2/3 support
  • Visual Configurator - Interactive parameter configuration panel
  • Code Generator - Generate Vue 2/3/Composable/Nuxt code snippets
  • Configuration Presets - Quick-start templates for common use cases
  • Monaco Editor - CDN-loaded code editor with syntax highlighting
  • Live Preview - Real-time directive effect preview

v1.8.0 (Planned - 2026-04-22) - Quality & Ecosystem

  • Test Coverage - 90%+ unit test coverage, E2E testing with Playwright
  • Performance Optimization - Bundle size optimization, tree-shaking improvements
  • VS Code Extension - Autocompletion, hover documentation, code snippets
  • CLI Tool - directix create, directix init, directix doctor, directix migrate

v1.9.0 (Planned - 2026-04-29) - Documentation & Community

  • Interactive Documentation - Live editing with instant preview
  • Real-world Examples - 10+ practical scenario examples
  • i18n Support - English, Chinese, Japanese documentation
  • Developer Experience - Improved error messages, DevTools integration
  • Plugin System - Community extension support

v1.10.0 (Planned - 2026-05-06) - Vue 3 Optimization & Security

  • Vue 3 Optimization Preview - Suspense, Teleport support
  • Mobile Optimization - Touch gestures, PWA support
  • Accessibility (A11y) - ARIA attributes, keyboard navigation
  • Security Enhancements - XSS protection, CSP compatibility

v1.11.0 (Planned - 2026-05-13) - Stability & Enterprise

  • Stability - Browser compatibility, edge case fixes
  • Performance Limits - Bundle ≤ 25KB, memory optimization
  • Enterprise Features - Permissions, audit logs, config center
  • v2.0 Migration Prep - Migration tool, breaking changes warnings

v2.0.0 (Future)

  • Vue 3 exclusive optimizations
  • Web Components support

Browser Support

| Browser | Version | |---------|---------| | Chrome | Latest | | Firefox | Latest | | Safari | Latest | | Edge | Latest |

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

License

MIT © 2024-present saqqdy