Skip to content

VueStripeP24BankElement

A dropdown selector for Polish banks enabling Przelewy24 (P24) payments, one of the most popular payment methods in Poland.

When to Use

Use VueStripeP24BankElement for Polish customers. Przelewy24 supports both PLN and EUR currencies and includes BLIK mobile payments.

What is P24 Bank Element?

P24 Bank Element provides a bank selector for Polish payments:

CapabilityDescription
Bank DropdownPre-populated list of 24+ Polish banks
BLIK SupportIncludes BLIK mobile payment option
Multi-CurrencySupports both PLN and EUR
Redirect FlowSeamless redirect to customer's bank
Instant NotificationReal-time payment confirmation

How It Works

mermaid
flowchart TD
    A["P24BankElement mounts inside StripeElements"] --> B["Renders bank dropdown<br/>Emits @ready when mounted"]
    B --> C["Customer selects bank from dropdown<br/>• mBank, PKO, ING, BLIK, etc."]
    C --> D["Emits @change with bank code<br/>{ complete: true, value: 'mbank' }"]
    D --> E{Submit form?}
    E -->|Yes| F["stripe.confirmP24Payment()<br/>with return_url + email"]
    F --> G["REDIRECT<br/>Customer sent to bank<br/>to authorize payment"]
    G --> H["Customer returns to return_url<br/>with payment result"]

Usage

vue
<template>
  <VueStripeProvider :publishable-key="publishableKey">
    <VueStripeElements>
      <VueStripeP24BankElement
        :options="options"
        @ready="onReady"
        @change="onChange"
      />
    </VueStripeElements>
  </VueStripeProvider>
</template>

<script setup>
import {
  VueStripeProvider,
  VueStripeElements,
  VueStripeP24BankElement
} from '@vue-stripe/vue-stripe'

const publishableKey = import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY

const options = {
  style: {
    base: {
      fontSize: '16px',
      color: '#424770'
    }
  }
}

const onReady = (element) => {
  console.log('P24 element ready', element)
}

const onChange = (event) => {
  console.log('Selected bank:', event.value)
  console.log('Complete:', event.complete)
}
</script>

Props

PropTypeRequiredDescription
optionsStripeP24BankElementOptionsNoElement configuration

Options Object

ts
interface StripeP24BankElementOptions {
  style?: {
    base?: StripeElementStyle
    complete?: StripeElementStyle
    empty?: StripeElementStyle
    invalid?: StripeElementStyle
  }
  value?: string  // Pre-select a bank by code
  disabled?: boolean
}

Style Properties

ts
interface StripeElementStyle {
  color?: string
  fontFamily?: string
  fontSize?: string
  fontWeight?: string
  iconColor?: string
  lineHeight?: string
  letterSpacing?: string
  padding?: string
  '::placeholder'?: { color?: string }
  ':focus'?: StripeElementStyle
  ':hover'?: StripeElementStyle
}

Events

EventPayloadDescription
@readyStripeP24BankElementEmitted when the element is fully rendered
@changeStripeP24BankElementChangeEventEmitted when bank selection changes
@focus-Emitted when the element gains focus
@blur-Emitted when the element loses focus

Change Event

ts
interface StripeP24BankElementChangeEvent {
  elementType: 'p24Bank'
  empty: boolean
  complete: boolean
  value?: string  // Bank code: 'mbank', 'pko', 'blik', etc.
}

Bank Codes

CodeBank Name
alior_bankAlior Bank
bank_millenniumBank Millennium
bank_nowy_bfgBank Nowy BFG S.A.
bank_pekao_saBank PEKAO S.A.
bank_spoldzielczyBank spółdzielczy
blikBLIK
bnp_paribasBNP Paribas
bozBOŻ
citi_handlowyCiti Handlowy
credit_agricoleCredit Agricole
e_transfer_pocztowy24e-Transfer Pocztowy24
getin_bankGetin Bank
idea_bankIdea Bank
ingING
inteligointeligo
mbankmBank
nest_przelewNest Przelew
noble_payNoble Pay
pkoPKO Bank Polski
plus_bankPlus Bank
santanderSantander
toyota_bankToyota Bank
velobankVeloBank
volkswagen_bankVolkswagen Bank

Slots

Loading Slot

Rendered while the element is initializing:

vue
<VueStripeP24BankElement>
  <template #loading>
    <div class="skeleton-loader">Loading banks...</div>
  </template>
</VueStripeP24BankElement>

Exposed Methods

Access these methods via template ref:

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

const p24Ref = ref()

const focusElement = () => p24Ref.value?.focus()
const clearElement = () => p24Ref.value?.clear()
</script>

<template>
  <VueStripeP24BankElement ref="p24Ref" />
  <button @click="focusElement">Focus</button>
  <button @click="clearElement">Clear Selection</button>
</template>
MethodDescription
focus()Focus the bank selector
blur()Blur the bank selector
clear()Clear the selection

Exposed Properties

PropertyTypeDescription
elementRef<StripeP24BankElement | null>The Stripe element instance
loadingRef<boolean>Whether the element is loading
errorRef<string | null>Current error message

Examples

Basic Usage

vue
<VueStripeP24BankElement
  @change="(e) => console.log('Bank:', e.value)"
/>

With Custom Styling

vue
<script setup>
const options = {
  style: {
    base: {
      fontSize: '16px',
      color: '#32325d',
      fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
      padding: '10px 12px'
    }
  }
}
</script>

<template>
  <VueStripeP24BankElement :options="options" />
</template>

Complete P24 Payment

vue
<script setup lang="ts">
import { ref } from 'vue'
import {
  VueStripeProvider,
  VueStripeElements,
  VueStripeP24BankElement,
  useStripe,
  useStripeElements
} from '@vue-stripe/vue-stripe'

const publishableKey = import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY
const selectedBank = ref('')
const isComplete = ref(false)
const email = ref('')

const handleChange = (event: any) => {
  selectedBank.value = event.value || ''
  isComplete.value = event.complete
}

// In child component inside provider:
const confirmPayment = async (clientSecret: string) => {
  const { stripe } = useStripe()
  const { elements } = useStripeElements()

  const p24Element = elements.value?.getElement('p24Bank')

  const { error } = await stripe.value.confirmP24Payment(
    clientSecret,
    {
      payment_method: {
        p24: p24Element,
        billing_details: {
          email: email.value // Required!
        }
      },
      return_url: `${window.location.origin}/payment-complete`
    }
  )

  if (error) {
    console.error(error.message)
  }
  // Customer redirected to bank
}
</script>

<template>
  <VueStripeProvider :publishable-key="publishableKey">
    <VueStripeElements>
      <form @submit.prevent="confirmPayment(clientSecret)">
        <input v-model="email" type="email" placeholder="Email (required)" />
        <VueStripeP24BankElement @change="handleChange" />
        <button :disabled="!isComplete || !email">Pay with P24</button>
      </form>
    </VueStripeElements>
  </VueStripeProvider>
</template>

TypeScript

ts
import { ref } from 'vue'
import { VueStripeP24BankElement } from '@vue-stripe/vue-stripe'
import type {
  StripeP24BankElement,
  StripeP24BankElementChangeEvent,
  StripeP24BankElementOptions
} from '@stripe/stripe-js'

// Options
const options: StripeP24BankElementOptions = {
  style: {
    base: {
      fontSize: '16px'
    }
  }
}

// Event handlers
const handleReady = (element: StripeP24BankElement) => {
  console.log('Ready:', element)
}

const handleChange = (event: StripeP24BankElementChangeEvent) => {
  console.log('Bank:', event.value)
  console.log('Complete:', event.complete)
}

// Template ref
const p24Ref = ref<InstanceType<typeof VueStripeP24BankElement>>()

Error Handling

ErrorCauseSolution
payment_intent_unexpected_statePaymentIntent not in expected stateCheck PaymentIntent status
redirect_failedBank redirect failedRetry the payment
email_invalidEmail not provided or invalidProvide valid email
payment_method_not_availableP24 not availableVerify account has P24 enabled

See Also

Released under the MIT License.