npm package: @myrasec/eu-captcha-vue
Description: This package provides an easy integration of EU CAPTCHA from Myra Security for Vue 3 and Nuxt.
Latest version: 1.0.0

This package provides an easy integration of EU CAPTCHA from Myra Security for Vue 3 and Nuxt.

For full documentation see **[docs.eu-captcha.eu](https://docs.eu-captcha.eu/)**.

You can [sign up for free](https://app.eu-captcha.eu/user-registration) to get a sitekey.

## Installation

```bash
npm i @myrasec/eu-captcha-vue
```

## Basic usage

```vue
<script setup lang="ts">
import { EuCaptcha, isEuCaptchaDone } from "@myrasec/eu-captcha-vue";

const captchaSitekey = "EUCAPTCHA_SITE_KEY";

function handleSubmit(): void {
  if (!isEuCaptchaDone()) {
    // challenge not yet complete
    return;
  }
  // proceed with form submission
}
</script>

<template>
  <form @submit.prevent="handleSubmit">
    <!-- your fields -->
    <EuCaptcha :sitekey="captchaSitekey" />
    <button type="submit">Submit</button>
  </form>
</template>
```

You can test the integration using any fake sitekey. If a sitekey does not exist, the captcha runs with default parameters which allow traffic to pass.

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `sitekey` | `string` | — | Your public sitekey (required) |
| `theme` | `string` | `"light"` | Visual theme: `"light"` or `"dark"` |
| `width` | `number` | `330` | Widget width in pixels |
| `height` | `number` | `100` | Widget height in pixels |
| `widgetId` | `string` | — | Custom widget ID. If omitted, an ID is auto-generated. Needed when calling `euCaptcha.execute()`. |
| `autostart` | `boolean` | `true` | Start the challenge automatically on mount. Set to `false` to defer until `euCaptcha.execute(widgetId)` is called. |
| `onComplete` | `(token: string) => void` | — | Called with the encoded token when the challenge completes. |
| `onExpired` | `() => void` | — | Called when the token expires (60 minutes after completion). |
| `onError` | `() => void` | — | Called when the challenge fails due to a network or server error. |

## Dark theme

```vue
<EuCaptcha :sitekey="captchaSitekey" theme="dark" />
```

## Custom width

```vue
<EuCaptcha :sitekey="captchaSitekey" :width="280" />
```

## Custom height

```vue
<EuCaptcha :sitekey="captchaSitekey" :height="60" />
```

## Deferred execution

Set `:autostart="false"` and provide a `widgetId`, then trigger the challenge manually:

```vue
<EuCaptcha
  :sitekey="captchaSitekey"
  widget-id="my-captcha"
  :autostart="false"
/>

<button @click="euCaptcha.execute('my-captcha')">Verify</button>
```

## Callbacks

```vue
<EuCaptcha
  :sitekey="captchaSitekey"
  :on-complete="(token) => console.log('token:', token)"
  :on-expired="() => console.log('token expired')"
  :on-error="() => console.log('challenge error')"
/>
```

## Querying state

Before submitting a form to a server, ensure EU CAPTCHA is done:

```ts
import { isEuCaptchaDone } from "@myrasec/eu-captcha-vue";

function handleSubmit(): void {
    if (!isEuCaptchaDone()) {
        // challenge not yet complete
        return;
    }
    // proceed with form submission
}
```

## Listening to state change

Listen for the `euCaptchaDone` window message to be notified when the challenge completes:

```ts
import { onMounted, onUnmounted } from "vue";

function listenForCaptchaDone(msg: MessageEvent): void {
    if (msg.data.type === "euCaptchaDone") {
        // enable submit button, update reactive state, etc.
    }
}

onMounted(() => window.addEventListener("message", listenForCaptchaDone, false));
onUnmounted(() => window.removeEventListener("message", listenForCaptchaDone, false));
```