vue-stripe-js
Advanced tools
Comparing version
{ | ||
"name": "vue-stripe-js", | ||
"version": "1.0.4", | ||
"description": "Vue 3 components for Stripe.js: Elements & Checkout", | ||
"main": "./dist/vue-stripe.umd.js", | ||
"module": "./dist/vue-stripe.es.js", | ||
"version": "2.0.0", | ||
"description": "Vue 3 components for Stripe.js", | ||
"type": "module", | ||
"main": "./dist/vue-stripe.js", | ||
"exports": { | ||
".": { | ||
"import": "./dist/vue-stripe.es.js", | ||
"require": "./dist/vue-stripe.umd.js", | ||
"types": "./types/vue-stripe.d.ts" | ||
"types": "./dist/vue-stripe.d.ts", | ||
"import": "./dist/vue-stripe.js", | ||
"browser": "./dist/vue-stripe.umd.cjs" | ||
} | ||
}, | ||
"types": "./types/vue-stripe.d.ts", | ||
"files": ["dist", "types"], | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "vue-tsc -b && vite build", | ||
"check:types": "publint && attw --pack . --ignore-rules=cjs-resolves-to-esm", | ||
"ci": "biome check && pnpm run build && pnpm run check:types" | ||
}, | ||
"files": ["dist"], | ||
"repository": { | ||
@@ -20,11 +25,4 @@ "type": "git", | ||
}, | ||
"keywords": [ | ||
"Vue", | ||
"Stripe", | ||
"Elements", | ||
"Checkout", | ||
"Payment", | ||
"Components" | ||
], | ||
"author": "Oleksandr Bystrikov", | ||
"keywords": ["Vue", "Stripe", "Elements", "Checkout", "Payments"], | ||
"author": "Oleksandr Bystrikov <https://github.com/softbeehive>", | ||
"license": "MIT", | ||
@@ -35,23 +33,19 @@ "homepage": "https://github.com/ectoflow/vue-stripe-js", | ||
}, | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "vuedx-typecheck . && vite build", | ||
"test": "jest" | ||
"dependencies": { | ||
"@stripe/stripe-js": "^5.5.0" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.17.10", | ||
"@babel/preset-env": "^7.16.0", | ||
"@babel/preset-typescript": "^7.16.0", | ||
"@stripe/stripe-js": "^1.21.1", | ||
"@types/node": "^17.0.33", | ||
"@types/stripe": "^8.0.417", | ||
"@vitejs/plugin-vue": "^2.3.3", | ||
"@vue/compiler-sfc": "^3.0.5", | ||
"@vuedx/typecheck": "^0.7.4", | ||
"@vuedx/typescript-plugin-vue": "^0.7.4", | ||
"jest": "^27.3.1", | ||
"typescript": "^4.1.3", | ||
"vite": "^2.6.14", | ||
"vue": "^3.2.21" | ||
"@arethetypeswrong/cli": "^0.17.2", | ||
"@biomejs/biome": "1.9.4", | ||
"@tailwindcss/vite": "4.0.0-beta.8", | ||
"@vitejs/plugin-vue": "^5.2.1", | ||
"@vue/tsconfig": "0.7.0", | ||
"publint": "^0.3.0", | ||
"tailwindcss": "4.0.0-beta.8", | ||
"typescript": "^5.7.3", | ||
"vite": "^6.0.7", | ||
"vite-plugin-dts": "^4.5.0", | ||
"vue": "^3.5.13", | ||
"vue-tsc": "^2.2.0" | ||
} | ||
} |
449
README.md
@@ -1,330 +0,216 @@ | ||
[](https://vshymanskyy.github.io/StandWithUkraine) | ||
# Vue Stripe.js | ||
Flexible and powerful Vue 3 components for Stripe. It's a glue between | ||
[Stripe.js](https://stripe.com/docs/js) and Vue component lifecycle. | ||
[](https://github.com/ectoflow/vue-stripe-js/actions) | ||
[](https://www.npmjs.com/package/vue-stripe-js) | ||
[](https://bundlephobia.com/result?p=vue-stripe-js) | ||
[](https://www.npmjs.com/package/vue-stripe-js) | ||
[](https://vshymanskyy.github.io/StandWithUkraine) | ||
# Quickstart | ||
Vue 3 components for Stripe. Build advanced payment integrations quickly. Easy to start, friendly DX, minimal abstractions, and full control. It's a glue between Stripe.js and Vue component lifecycle. | ||
### 1. Install | ||
### [**Become a sponsor** 💜](https://github.com/sponsors/softbeehive) | ||
Consider supporting efforts to make this project healthy and sustainable. Thank you! | ||
**npm** | ||
## Quickstart ⚡️ | ||
```bash | ||
npm i vue-stripe-js @stripe/stripe-js | ||
``` | ||
### Upgrade | ||
• [**Upgrade guide**](docs/UPGRADE_V1_TO_V2.md) | ||
• **[Docs v1](https://github.com/ectoflow/vue-stripe-js/tree/v1.0.4)** | ||
**yarn** | ||
### 1. Install | ||
```bash | ||
yarn add vue-stripe-js @stripe/stripe-js | ||
npm i vue-stripe-js @stripe/stripe-js | ||
``` | ||
**pnpm** | ||
```bash | ||
pnpm add vue-stripe-js @stripe/stripe-js | ||
``` | ||
### 2. Load Stripe.js | ||
```ts | ||
```vue | ||
<script setup lang="ts"> | ||
import { onBeforeMount, ref } from "vue" | ||
import { loadStripe } from "@stripe/stripe-js" | ||
import { defineComponent, onBeforeMount, ref } from "vue" | ||
import type { Stripe } from "@stripe/stripe-js" | ||
export default defineComponent({ | ||
// ... | ||
setup() { | ||
onBeforeMount(() => { | ||
const stripeLoaded = ref(false) | ||
const stripePromise = loadStripe("your_key") | ||
stripePromise.then(() => { | ||
stripeLoaded.value = true | ||
}) | ||
}) | ||
}, | ||
const publishableKey = ref('') | ||
const stripe = ref<Stripe | null>(null) | ||
onBeforeMount(async() => { | ||
stripe.value = await loadStripe(publishableKey.value) | ||
}) | ||
</script> | ||
``` | ||
> Alternatively, you can load Stripe library by including script tag. Just make | ||
> sure it's ready before your stripe components mount. | ||
Alternatively, include a script tag. Make sure Stripe.js is loaded before you mount Vue components. | ||
``` | ||
```html | ||
<script src="https://js.stripe.com/v3/"></script> | ||
``` | ||
### 3. Card payment (default) | ||
### 3. Payment Element | ||
Based on – [deferred payment guide](https://docs.stripe.com/payments/accept-a-payment-deferred?type=payment) | ||
```vue | ||
<template> | ||
<StripeElements | ||
<form | ||
v-if="stripeLoaded" | ||
v-slot="{ elements, instance }" // attention: important part! | ||
ref="elms" | ||
:stripe-key="stripeKey" | ||
:instance-options="instanceOptions" | ||
:elements-options="elementsOptions" | ||
@submit.prevent="handleSubmit" | ||
> | ||
<StripeElement | ||
ref="card" | ||
:elements="elements" | ||
:options="cardOptions" | ||
/> | ||
</StripeElements> | ||
<button type="button" @click="pay">Pay</button> | ||
<StripeElements | ||
:stripe-key="stripeKey" | ||
:instance-options="stripeOptions" | ||
:elements-options="elementsOptions" | ||
ref="elementsComponent" | ||
> | ||
<StripeElement | ||
type="payment" | ||
:options="paymentElementOptions" | ||
ref="paymentComponent" | ||
/> | ||
</StripeElements> | ||
<button | ||
type="submit" | ||
> | ||
Submit | ||
</button> | ||
</form> | ||
</template> | ||
<script lang="ts"> | ||
import { StripeElements, StripeElement } from 'vue-stripe-js' | ||
import { loadStripe } from '@stripe/stripe-js' | ||
import { defineComponent, ref, onBeforeMount } from 'vue' | ||
<script setup lang="ts"> | ||
import { onBeforeMount, ref } from "vue" | ||
import { loadStripe } from "@stripe/stripe-js" | ||
import { StripeElements, StripeElement } from "vue-stripe-js" | ||
export default defineComponent({ | ||
name: 'CardOnly', | ||
import type { | ||
StripeElementsOptionsMode, | ||
StripePaymentElementOptions, | ||
} from "@stripe/stripe-js" | ||
components: { | ||
StripeElements, | ||
StripeElement, | ||
const stripeKey = ref("pk_test_f3duw0VsAEM2TJFMtWQ90QAT") | ||
const stripeOptions = ref({ | ||
// https://stripe.com/docs/js/initializing#init_stripe_js-options | ||
}) | ||
const elementsOptions = ref<StripeElementsOptionsMode>({ | ||
// https://stripe.com/docs/js/elements_object/create#stripe_elements-options | ||
mode: "payment", | ||
amount: 1099, | ||
currency: "usd", | ||
appearance: { | ||
theme: "flat", | ||
}, | ||
setup() { | ||
const stripeKey = ref('pk_test_TYooMQauvdEDq54NiTphI7jx') // test key | ||
const instanceOptions = ref({ | ||
// https://stripe.com/docs/js/initializing#init_stripe_js-options | ||
}) | ||
const elementsOptions = ref({ | ||
// https://stripe.com/docs/js/elements_object/create#stripe_elements-options | ||
}) | ||
const cardOptions = ref({ | ||
// https://stripe.com/docs/stripe.js#element-options | ||
value: { | ||
postalCode: '12345', | ||
}, | ||
}) | ||
const stripeLoaded = ref(false) | ||
const card = ref() | ||
const elms = ref() | ||
onBeforeMount(() => { | ||
const stripePromise = loadStripe(stripeKey.value) | ||
stripePromise.then(() => { | ||
stripeLoaded.value = true | ||
}) | ||
}) | ||
const pay = () => { | ||
// Get stripe element | ||
const cardElement = card.value.stripeElement | ||
// Access instance methods, e.g. createToken() | ||
elms.value.instance.createToken(cardElement).then((result: object) => { | ||
// Handle result.error or result.token | ||
console.log(result) | ||
}) | ||
} | ||
return { | ||
stripeKey, | ||
stripeLoaded, | ||
instanceOptions, | ||
elementsOptions, | ||
cardOptions, | ||
card, | ||
elms, | ||
pay | ||
} | ||
} | ||
}) | ||
</script> | ||
``` | ||
const paymentElementOptions = ref<StripePaymentElementOptions>({ | ||
// https://docs.stripe.com/js/elements_object/create_payment_element#payment_element_create-options | ||
}) | ||
const stripeLoaded = ref(false) | ||
const clientSecret = ref("") | ||
### 4. Payment element (requires backend) | ||
// Define component refs | ||
const elementsComponent = ref() | ||
const paymentComponent = ref() | ||
1. Add server code by following | ||
[stripe guide](https://docs.stripe.com/payments/quickstart?lang=node) | ||
1. Grab `clientSecret` from the payment intent | ||
1. Pass it to `elements-options` | ||
onBeforeMount(() => { | ||
loadStripe(stripeKey.value).then(() => { | ||
stripeLoaded.value = true | ||
```vue | ||
<template> | ||
<StripeElements | ||
... | ||
:elements-options="elementsOptions" | ||
> | ||
<StripeElement | ||
type="payment" | ||
... | ||
/> | ||
</StripeElements> | ||
<template /> | ||
``` | ||
// Good place to call your backend to create PaymentIntent | ||
// Skipping to the point when you got client_secret | ||
```ts | ||
const elementsOptions = ref({ | ||
clientSecret: "grab_it_from_payment_intent", | ||
// https://stripe.com/docs/js/elements_object/create#stripe_elements-options | ||
// clientSecret.value = client_secret | ||
}) | ||
}) | ||
``` | ||
#### It works! | ||
async function handleSubmit() { | ||
// Confirm the PaymentIntent using the details collected by the Payment Element | ||
const stripeInstance = elementsComponent.value?.instance | ||
const elements = elementsComponent.value?.elements | ||
<img width="840" alt="image" src="https://github.com/user-attachments/assets/0619f7b5-a70f-48a1-84c4-c75bf9fc6ded" /> | ||
if (stripeInstance) { | ||
const { error } = await stripeInstance.confirmPayment({ | ||
elements, | ||
clientSecret: clientSecret.value, | ||
confirmParams: { | ||
return_url: "https://example.com/order/123/complete", | ||
}, | ||
}) | ||
### 5. Use elements like lego | ||
if (error) { | ||
// This point is only reached if there's an immediate error when | ||
// confirming the payment. Show the error to your customer (for example, payment details incomplete) | ||
console.log(error) | ||
} else { | ||
// Your customer is redirected to your `return_url`. For some payment | ||
// methods like iDEAL, your customer is redirected to an intermediate | ||
// site first to authorize the payment, then redirected to the `return_url`. | ||
} | ||
} | ||
} | ||
</script> | ||
```vue | ||
<StripeElements | ||
v-slot="{ elements }" | ||
:stripe-key="stripeKey" | ||
:instance-options="instanceOptions" | ||
:elements-options="elementsOptions" | ||
> | ||
<StripeElement | ||
type="cardNumber" | ||
:elements="elements" | ||
:options="cardNumberOptions" | ||
/> | ||
<StripeElement | ||
type="postalCode" | ||
:elements="elements" | ||
:options="postalCodeOptions" | ||
/> | ||
</StripeElements> | ||
``` | ||
# Types | ||
## Examples 🌿 | ||
```ts | ||
import types { | ||
initStripe, | ||
createElements, | ||
createElement, | ||
StripeElements, | ||
StripeElement | ||
} from 'vue-stripe-js' | ||
``` | ||
Thanks to the Provider Pattern used in StripeElements, you get minimalist tools with full access to Stripe.js methods and properties. This results in better developer experience (DX), simpler code, and fewer bugs. | ||
# API Reference | ||
These examples use Vue Composition API and TypeScript. | ||
## StripeElements.vue | ||
- [All](examples/) | ||
- [Payment](examples/PaymentElementDeferred.vue) | ||
- [Card](examples/CardElement.vue) | ||
- [Express Checkout](examples/ExpressCheckoutElement.vue) | ||
Think of it as of individual group of elements. It creates stripe instance and | ||
elements object. | ||
### Screenshot | ||
```js | ||
import { StripeElements } from "vue-stripe-js" | ||
``` | ||
 | ||
### props | ||
## Advanced integration 🏗️ | ||
```js | ||
// https://stripe.com/docs/js/initializing#init_stripe_js-options | ||
stripeKey: { | ||
type: String, | ||
required: true, | ||
}, | ||
// https://stripe.com/docs/js/elements_object/create#stripe_elements-options | ||
instanceOptions: { | ||
type: Object, | ||
default: () => ({}), | ||
}, | ||
// https://stripe.com/docs/stripe.js#element-options | ||
elementsOptions: { | ||
type: Object, | ||
default: () => ({}), | ||
}, | ||
``` | ||
All features of Stripe.js are available in two components. The benefits of Vue solution: element is created and destroyed automatically, options are reactive, event listeners are attached to StripeElement. Simple and future-proof. | ||
### data | ||
🥇 **Most important property is type** 🥇 | ||
You can access `instance` and `elements` by adding ref to StripeElements | ||
component. | ||
```js | ||
// StripeElements.vue exposes | ||
{ | ||
elements, | ||
instance, | ||
elementsUsable, | ||
} | ||
``` | ||
### default scoped slot | ||
Elegant solution for props. Really handy because you can make stripe `instance` | ||
and `elements` objects available to all children without adding extra code. | ||
```vue | ||
<!-- Cool, isn't it? --> | ||
<StripeElements v-slot="{ elements, instance }"> | ||
<StripeElement :elements="elements" /> | ||
<CustomComponent :instance="instance" /> | ||
```html | ||
<StripeElements> | ||
<StripeElement type="payment" /> | ||
</StripeElements> | ||
``` | ||
## StripeElement.vue | ||
Available types | ||
```ts | ||
type StripeElementType = | ||
| 'address' | ||
| 'affirmMessage' | ||
| 'afterpayClearpayMessage' | ||
| 'auBankAccount' | ||
| 'card' | ||
| 'cardNumber' | ||
| 'cardExpiry' | ||
| 'cardCvc' | ||
| 'currencySelector' | ||
| 'epsBank' | ||
| 'expressCheckout' | ||
| 'fpxBank' | ||
| 'iban' | ||
| 'idealBank' | ||
| 'p24Bank' | ||
| 'payment' | ||
| 'paymentMethodMessaging' | ||
| 'paymentRequestButton' | ||
| 'linkAuthentication' | ||
| 'shippingAddress' | ||
| 'issuingCardNumberDisplay' | ||
| 'issuingCardCvcDisplay' | ||
| 'issuingCardExpiryDisplay' | ||
| 'issuingCardPinDisplay' | ||
| 'issuingCardCopyButton' | ||
Universal and type agnostic component. Create any element supported by Stripe. | ||
```js | ||
import { StripeElement } from "vue-stripe-js" | ||
// Check actual element types in @stripe/stripe-js | ||
``` | ||
### props | ||
## Events | ||
```js | ||
{ | ||
// elements object | ||
// https://stripe.com/docs/js/elements_object/create | ||
elements: { | ||
type: Object as () => StripeElementsWithoutOverload, | ||
required: true, | ||
}, | ||
// type of the element | ||
// https://stripe.com/docs/js/elements_object/create_element?type=card | ||
type: { | ||
type: String as () => StripeElementType, | ||
default: () => 'card', | ||
}, | ||
// element options | ||
// https://stripe.com/docs/js/elements_object/create_element?type=card#elements_create-options | ||
options: { | ||
type: Object as () => StripeElementOptions, | ||
default: () => ({}), | ||
}, | ||
}, | ||
```html | ||
<StripeElement @blur="doSomething" /> | ||
``` | ||
### data | ||
```js | ||
{ | ||
stripeElement, | ||
domElement, | ||
mountPoint, | ||
} | ||
``` | ||
### options | ||
Element options are reactive. Recommendation: don't use v-model on | ||
`StripeElement`, instead pass value via options. | ||
```js | ||
setup() { | ||
const elementOptions = ref({ | ||
value: { | ||
postalCode: '12345' | ||
} | ||
}) | ||
const changePostalCode = (postalCode) => { | ||
elementOptions.value.postalCode = postalCode | ||
} | ||
}, | ||
``` | ||
### events | ||
Following events are emitted on StripeElement | ||
@@ -338,10 +224,29 @@ | ||
- escape | ||
- loaderror | ||
- loaderstart | ||
## Styling | ||
Add classes to components | ||
```html | ||
<StripeElement :elements="elements" @blur="doSomething" /> | ||
<StripeElements class="border"> | ||
<StripeElement class="p-4" type="card" :options="cardOptions" /> | ||
</StripeElements> | ||
``` | ||
# Styles | ||
Style element via options - [read documentation](https://stripe.com/docs/js/appendix/style) | ||
No base style included. Main reason: overriding it isn't fun. Style as you wish | ||
via element options: [see details](https://stripe.com/docs/js/appendix/style). | ||
```ts | ||
const cardOptions = ref<StripeCardElementOptions>({ | ||
style: { | ||
base: { | ||
iconColor: "green", | ||
}, | ||
invalid: { | ||
iconColor: "red", | ||
}, | ||
}, | ||
}) | ||
``` |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
29900
51.32%12
-14.29%7
16.67%313
22.27%Yes
NaN1
Infinity%2
100%252
-27.38%1
Infinity%+ Added
+ Added