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

vue-nuxt-permission

v2.0.6

Published

A lightweight, flexible permission directive and router guard for Vue 3

Readme

🔐 vue-permission

A powerful, flexible permission management plugin for Vue 3
Provides a declarative directive (v-permission), route protection (globalGuard), permission evaluation utilities, Base64-encoded localStorage persistence, and caching.


🚀 Features

  • v-permission directive: show/hide/remove elements based on permissions
  • 🛡️ Route guard globalGuard with fallback redirection
  • Performance: Fast with permission caching
  • 🔀 Complex logic: Supports and, or, regex, startWith, exact, etc.
  • 🔒 Security: Stores permissions in Base64-encoded localStorage
  • 🔧 Flexible: Simple API & customizable behavior
  • 📱 Reactive: Works with both static arrays or reactive Ref<string[]>
  • 🎯 TypeScript: Full TypeScript support

📦 Installation

npm install vue-permission
# or
yarn add vue-permission
# or
pnpm add vue-permission

🧩 Quick Setup

Vue 3 App

// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import { PermissionPlugin } from "vue-permission";

const app = createApp(App);

app.use(PermissionPlugin, {
  permissions: ["user.create", "user.view", "admin.panel"],
  developmentMode: process.env.NODE_ENV === "development",
});

app.mount("#app");

Nuxt 3

// plugins/vue-permission.client.ts
import { defineNuxtPlugin } from "#app";
import { PermissionPlugin } from "vue-permission";

export default defineNuxtPlugin((nuxtApp) => {
  // Get permissions from your auth store/API
  const permissions = ["user.view", "user.edit"];

  nuxtApp.vueApp.use(PermissionPlugin, {
    permissions,
    developmentMode: process.env.NODE_ENV === "development",
  });
});

🎯 Using v-permission Directive

Basic Usage

<template>
  <!-- Remove element if permission is missing -->
  <button v-permission="'user.create'">Create User</button>

  <!-- Multiple permissions (OR logic) -->
  <button v-permission="['user.edit', 'user.update']">Edit User</button>

  <!-- Hide instead of remove -->
  <div v-permission:show="'admin.panel'">Admin Panel</div>
</template>

Advanced Configuration

<template>
  <!-- Require ALL permissions (AND logic) -->
  <button
    v-permission="{ permissions: ['user.edit', 'admin.users'], mode: 'and' }"
  >
    Advanced Edit
  </button>

  <!-- Regex pattern matching -->
  <div v-permission="{ permissions: ['^admin\\..*'], mode: 'regex' }">
    Any Admin Permission
  </div>

  <!-- Exact match only -->
  <button v-permission="{ permissions: ['user'], mode: 'exact' }">
    Exact Match
  </button>

  <!-- Start with pattern -->
  <nav v-permission="{ permissions: ['menu.'], mode: 'startWith' }">
    Navigation Menu
  </nav>
</template>

Directive Modifiers

| Modifier | Description | Example | | -------- | --------------------------------------------- | --------------------------------- | | :show | Hide with display: none instead of removing | v-permission:show="'user.view'" | | .once | Check permission only once on mount | v-permission.once="'user.view'" | | .lazy | Don't react to permission changes | v-permission.lazy="'user.view'" |

<template>
  <!-- Combined modifiers -->
  <div v-permission:show.once="'user.dashboard'">
    Dashboard (hidden, checked once)
  </div>
</template>

🧭 Route Protection

Setup Router Guard

// router/index.ts
import { createRouter, createWebHistory } from "vue-router";
import { globalGuard } from "vue-permission";

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: "/login",
      component: () => import("@/views/Login.vue"),
      meta: { isAuthRoute: true },
    },
    {
      path: "/dashboard",
      component: () => import("@/views/Dashboard.vue"),
      meta: {
        requiresAuth: true,
        checkPermission: true,
        permissions: ["dashboard.view"],
      },
    },
    {
      path: "/admin",
      component: () => import("@/views/Admin.vue"),
      meta: {
        requiresAuth: true,
        checkPermission: true,
        permissions: { permissions: ["admin.*"], mode: "regex" },
      },
    },
  ],
});

// Configure the guard
router.beforeEach((to, from, next) => {
  globalGuard(to, from, next, {
    authRoutes: [{ path: "/login" }, { path: "/register" }],
    protectedRoutes: router.options.routes,
    getAuthState: () => {
      // Return your auth state
      const authStore = useAuthStore(); // or your auth logic
      return {
        isAuthenticated: authStore.isAuthenticated,
        user: authStore.user,
      };
    },
  });
});

export default router;

Route Meta Options

| Property | Type | Description | | ----------------- | ---------------------------------------- | --------------------------------------------- | | requiresAuth | boolean | Redirect unauthenticated users to login | | checkPermission | boolean | Enable permission checking for this route | | permissions | string \| string[] \| PermissionObject | Required permissions | | isAuthRoute | boolean | Mark as authentication route (login/register) |

// Example route configurations
const routes = [
  {
    path: "/users",
    component: UsersList,
    meta: {
      requiresAuth: true,
      checkPermission: true,
      permissions: ["users.view"], // Simple permission
    },
  },
  {
    path: "/settings",
    component: Settings,
    meta: {
      requiresAuth: true,
      checkPermission: true,
      permissions: ["settings.view", "admin.panel"], // OR logic
    },
  },
  {
    path: "/advanced-admin",
    component: AdvancedAdmin,
    meta: {
      requiresAuth: true,
      checkPermission: true,
      permissions: {
        // Complex logic
        permissions: ["admin.advanced", "super.user"],
        mode: "and",
      },
    },
  },
];

🧠 Permission Checking Utilities

hasPermission() Function

import { hasPermission } from "vue-permission";

// In component
export default {
  async mounted() {
    // Simple check
    const canEdit = await hasPermission("user.edit");

    // Multiple permissions (OR)
    const canAccess = await hasPermission(["user.view", "admin.panel"]);

    // Complex logic
    const isAdmin = await hasPermission({
      permissions: ["admin.*"],
      mode: "regex",
    });

    // Use in template
    this.showEditButton = canEdit;
  },
};
<!-- In Composition API -->
<script setup>
import { ref, onMounted } from "vue";
import { hasPermission } from "vue-permission";

const canCreateUser = ref(false);

onMounted(async () => {
  canCreateUser.value = await hasPermission("user.create");
});
</script>

<template>
  <button v-if="canCreateUser">Create User</button>
</template>

⚙️ Configuration & Management

Dynamic Permission Updates

import { configurePermission } from "vue-permission";

// After login
async function login(credentials) {
  const response = await api.login(credentials);
  const userPermissions = response.user.permissions;

  // Update permissions
  configurePermission(userPermissions, {
    developmentMode: process.env.NODE_ENV === "development",
  });
}

// After logout
function logout() {
  configurePermission([], {
    developmentMode: process.env.NODE_ENV === "development",
  });
}

Reactive Permissions with Pinia/Vuex

// stores/auth.ts
import { defineStore } from "pinia";
import { ref } from "vue";
import { configurePermission } from "vue-permission";

export const useAuthStore = defineStore("auth", () => {
  const permissions = ref<string[]>([]);

  function setPermissions(newPermissions: string[]) {
    permissions.value = newPermissions;
    configurePermission(permissions); // Pass reactive ref
  }

  return { permissions, setPermissions };
});

Cache Management

import { clearPermissionCache } from "vue-permission";

// Clear cache when permissions change
function updateUserRole() {
  clearPermissionCache(); // Clear to force re-evaluation
  configurePermissionDirective(newPermissions);
}

🎨 Permission Modes

| Mode | Description | Example | | ----------- | -------------------------------- | ------------------------------------------------------------ | | or | Any permission matches (default) | ['user.view', 'admin.panel'] | | and | All permissions required | { permissions: ['user.edit', 'user.delete'], mode: 'and' } | | exact | Exact string match only | { permissions: ['admin'], mode: 'exact' } | | startWith | Permission starts with pattern | { permissions: ['admin.'], mode: 'startWith' } | | endWith | Permission ends with pattern | { permissions: ['.view'], mode: 'endWith' } | | regex | Regular expression matching | { permissions: ['^admin\\..*'], mode: 'regex' } |

Mode Examples

<template>
  <!-- OR: User needs either permission -->
  <button v-permission="['user.create', 'admin.users']">Create</button>

  <!-- AND: User needs both permissions -->
  <button
    v-permission="{ permissions: ['user.edit', 'user.delete'], mode: 'and' }"
  >
    Full Edit Access
  </button>

  <!-- REGEX: Any admin permission -->
  <div v-permission="{ permissions: ['^admin\\.'], mode: 'regex' }">
    Admin Section
  </div>

  <!-- START WITH: Any menu permission -->
  <nav v-permission="{ permissions: ['menu.'], mode: 'startWith' }">
    Menu Items
  </nav>
</template>

🛠️ API Reference

Plugin Options

interface PluginOptions {
  permissions?: string[] | Ref<string[]>;
  developmentMode?: boolean;
}

Permission Value Types

type PermissionValue =
  | string // Single permission
  | string[] // Multiple permissions (OR)
  | PermissionObject; // Complex permission object

interface PermissionObject {
  permissions: string[];
  mode: "and" | "or" | "startWith" | "endWith" | "exact" | "regex";
}

Utility Functions

// Configure permissions
configurePermission(permissions: string[] | Ref<string[]>, options?: { developmentMode?: boolean })

// Check permissions programmatically
hasPermission(permission: PermissionValue, userPermissions?: string[]): Promise<boolean>

// Initialize from storage
initPermissionDirectiveIfNeeded(): void

// Clear cache
clearPermissionCache(): void

// Get current permissions
getCurrentPermissions(): string[]

🔍 Advanced Examples

Dynamic Role-Based Menu

<template>
  <nav class="sidebar">
    <router-link
      v-permission="'dashboard.view'"
      to="/dashboard"
      class="nav-item"
    >
      Dashboard
    </router-link>

    <router-link
      v-permission="['users.view', 'admin.users']"
      to="/users"
      class="nav-item"
    >
      Users
    </router-link>

    <div
      v-permission="{ permissions: ['^admin\\.'], mode: 'regex' }"
      class="admin-section"
    >
      <h3>Admin</h3>
      <router-link v-permission="'admin.settings'" to="/admin/settings"
        >Settings</router-link
      >
      <router-link v-permission="'admin.reports'" to="/admin/reports"
        >Reports</router-link
      >
    </div>
  </nav>
</template>

Conditional Form Fields

<template>
  <form @submit="handleSubmit">
    <input v-model="user.name" placeholder="Name" />
    <input v-model="user.email" placeholder="Email" />

    <!-- Only admins can change roles -->
    <select v-permission:show="'admin.users'" v-model="user.role">
      <option value="user">User</option>
      <option value="admin">Admin</option>
    </select>

    <!-- Different submit buttons based on permissions -->
    <button v-permission="'user.create'" type="submit">Create User</button>

    <button
      v-permission="{ permissions: ['user.edit', 'admin.users'], mode: 'and' }"
      type="submit"
    >
      Advanced Save
    </button>
  </form>
</template>

🐛 Debugging

Development Mode

app.use(PermissionPlugin, {
  permissions: userPermissions,
  developmentMode: true, // Enables console warnings and logs
});

Common Issues

  1. Permissions not updating: Clear cache after permission changes
clearPermissionCache();
configurePermission(newPermissions);
  1. Route guard not working: Ensure getAuthState returns correct values
getAuthState: () => ({
  isAuthenticated: !!localStorage.getItem("token"),
  user: JSON.parse(localStorage.getItem("user") || "{}"),
});
  1. Directive not reactive: Use Ref<string[]> for reactive permissions
const permissions = ref(["user.view"]);
configurePermissionDirective(permissions);

📂 Project Structure

vue-permission/
├── src/
│   ├── directives/
│   │   └── v-permission.ts      # Directive implementation
│   ├── guards/
│   │   └── globalGuard.ts       # Route guard logic
│   ├── utils/
│   │   ├── permissionCache.ts   # Caching system
│   │   ├── permissionStorage.ts # LocalStorage Base64 persistence
│   │   └── permissionHelpers.ts # Core permission logic
│   ├── plugin.ts                # Vue plugin registration
│   ├── index.ts                 # Main exports
│   └── types.ts                 # TypeScript definitions
├── package.json
└── README.md

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

MIT © kerolos


🆕 Changelog

v2.0.0

  • Rename configurePermissionDirectiveconfigurePermission
  • Add .lazy and .once directive modifiers
  • Optional userPermissions param in hasPermission
  • Improved caching and Base64 storage wording
  • Updated docs and examples