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

recaptcha-vue

v1.0.0

Published

Lightweight Vue 3 reCAPTCHA v2 checkbox component with TypeScript, Vite library build, and Inertia.js support

Readme

recaptcha-vue

Lightweight, zero-dependency Vue 3 component for Google reCAPTCHA v2 (checkbox)
with full TypeScript support, Vite library build, and first-class Laravel + Inertia.js integration.

npm license CI


Features

  • Vue 3 Composition API + <script setup>
  • 🔑 TypeScript — full types for props, emits, and the exposed API
  • 🧩 useRecaptcha composable — reactive token & isVerified state
  • 🔁 v-model support — bind the verified token directly
  • 🌐 Multiple instances — safe to use more than one widget per page
  • 🎨 Theminglight / dark, normal / compact
  • 🌍 Language — pass any BCP 47 code (hl param)
  • ⏱️ Load timeout — emits error if the script never loads
  • 🔌 Laravel + Inertia.js — ready-to-use controller & form examples
  • 📦 ESM + CJS dual build via Vite

Installation

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

Vue 3.3+ is required as a peer dependency.


Quick start

1. Get your reCAPTCHA v2 keys

Register at https://www.google.com/recaptcha/admin.
Choose reCAPTCHA v2 → "I'm not a robot" Checkbox.

Test keys (always pass, never use in production):
Site key: 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
Secret key: 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe

2. Add your site key to the environment

# .env
VITE_RECAPTCHA_SITE_KEY=your_site_key_here

3. Use the component

<script setup lang="ts">
import { ref } from 'vue'
import { VueRecaptcha, useRecaptcha } from 'recaptcha-vue'

const siteKey = import.meta.env.VITE_RECAPTCHA_SITE_KEY
const recaptchaRef = ref<InstanceType<typeof VueRecaptcha> | null>(null)
const { token, isVerified, onVerify, onExpire, onError } = useRecaptcha()

function submit() {
  console.log('Token to send to server:', token.value)
  // After submit, reset the widget:
  recaptchaRef.value?.reset()
}
</script>

<template>
  <VueRecaptcha
    ref="recaptchaRef"
    :sitekey="siteKey"
    @verify="onVerify"
    @expire="onExpire"
    @error="onError"
  />
  <button :disabled="!isVerified" @click="submit">Submit</button>
</template>

4. Register globally (optional)

// main.ts
import { createApp } from 'vue'
import RecaptchaPlugin from 'recaptcha-vue'
import App from './App.vue'

createApp(App).use(RecaptchaPlugin).mount('#app')

Props

| Prop | Type | Default | Description | |---|---|---|---| | sitekey | string | required | Your reCAPTCHA v2 site key | | theme | 'light' \| 'dark' | 'light' | Widget color scheme | | size | 'normal' \| 'compact' | 'normal' | Widget size | | tabindex | number | 0 | Tab index | | loadingTimeout | number | 30000 | ms before emitting error if widget never loads | | language | string | '' | BCP 47 language code, e.g. 'fr', 'ar' | | badge | 'bottomright' \| 'bottomleft' \| 'inline' | 'bottomright' | Badge position (invisible size only) | | isolated | boolean | false | Isolate widget from others on the page | | modelValue | string | '' | v-model — holds the verified token |


Events

| Event | Payload | Description | |---|---|---| | verify | token: string | User completed the challenge; token ready to send to server | | expire | — | Token expired; user must re-verify | | error | — | Widget or network error | | widget-id | id: number | Internal widget ID after render | | update:modelValue | token: string | v-model update |


Exposed API (via ref)

const recaptchaRef = ref<InstanceType<typeof VueRecaptcha> | null>(null)

recaptchaRef.value?.reset()        // Reset the widget
recaptchaRef.value?.execute()      // Programmatically trigger (compact / invisible)
recaptchaRef.value?.getResponse()  // Get current token string

useRecaptcha composable

const {
  token,       // Ref<string>  — current token ('' when expired / error)
  isVerified,  // Ref<boolean> — true when a valid token exists
  onVerify,    // (token: string) => void
  onExpire,    // () => void
  onError,     // () => void
  reset,       // () => void — clears local state (call recaptchaRef.reset() too)
} = useRecaptcha()

v-model

<script setup>
import { ref } from 'vue'
import { VueRecaptcha } from 'recaptcha-vue'

const captchaToken = ref('')
</script>

<template>
  <VueRecaptcha v-model="captchaToken" sitekey="..." />
  <p>Token: {{ captchaToken }}</p>
</template>

Laravel + Inertia.js integration

Front-end — ContactForm.vue

See examples/inertia/ContactForm.vue for a full working example using useForm from @inertiajs/vue3.

Key points:

  1. Store the verified token in form.recaptcha_token
  2. Always reset the widget after a successful or failed submission

Back-end — ContactController.php

See examples/laravel/ContactController.php.

Add to config/services.php:

'recaptcha' => [
    'site_key'   => env('RECAPTCHA_SITE_KEY'),
    'secret_key' => env('RECAPTCHA_SECRET_KEY'),
],

Add to .env (server-side):

RECAPTCHA_SITE_KEY=your_site_key
RECAPTCHA_SECRET_KEY=your_secret_key

# Expose site key to Vite:
VITE_RECAPTCHA_SITE_KEY="${RECAPTCHA_SITE_KEY}"

Verify the token inside your controller:

$response = Http::asForm()->post('https://www.google.com/recaptcha/api/siteverify', [
    'secret'   => config('services.recaptcha.secret_key'),
    'response' => $request->input('recaptcha_token'),
    'remoteip' => $request->ip(),
]);

if (! $response->json('success')) {
    throw ValidationException::withMessages([
        'recaptcha_token' => 'reCAPTCHA verification failed. Please try again.',
    ]);
}

Dark theme example

<VueRecaptcha
  :sitekey="siteKey"
  theme="dark"
  size="compact"
  language="ar"
  @verify="onVerify"
/>

Multiple instances on one page

Each <VueRecaptcha> instance manages its own unique widget ID and global callback names, so you can safely render multiple widgets:

<VueRecaptcha :sitekey="siteKey" @verify="handleLoginCaptcha" />
<VueRecaptcha :sitekey="siteKey" @verify="handleSignupCaptcha" />

Development

git clone https://github.com/Souhailmakni/recaptcha-vue.git
cd recaptcha-vue
npm install
npm run build      # produce dist/
npm run typecheck  # vue-tsc

Publishing to npm

# Bump version in package.json, then:
git commit -am "release: v1.0.1"
git tag v1.0.1
git push --follow-tags
# GitHub Actions will publish automatically on 'release:' commits to main
# Or publish manually:
npm publish --access public

License

MIT © Souhail Makni