Problem/Motivation

We are building a checkout experience using a multistep Webform (in our case, a donation flow), and have encountered several UX limitations with the current Commerce Webform Order approach, which redirects users to the standard Commerce checkout page after submission.

This redirect introduces multiple UX issues for us, such as:

  • Inconsistent layout and theming: the Webform is rendered using Canvas with a fully controlled layout, while the Commerce checkout page cannot easily be made Canvas-compatible, resulting in a visual and structural break in the user journey
  • Loss of smooth step transitions: our Webform relies on AJAX-driven multistep navigation for a seamless experience, which is interrupted by a full-page redirect
  • Broken navigation behaviour: using the browser “Back” button after reaching the checkout can lead to unexpected states (e.g. already submitted form or empty form), which degrades UX and may impact conversion

More broadly, this pattern prevents implementing a fully integrated, uninterrupted checkout flow within Webform, which is increasingly important for high-conversion use cases like donations.

At the same time, we still need to:

  • Persist user progress into a Commerce Order as the form is being filled (for analytics and operational needs)
  • Avoid saving/storing the actual Webform submission, as long as all data is stored in Commerce

Proposed resolution

We recognise that fully embedding Commerce payment processing into Webform would be a complex and high-effort task. Instead, we propose a lighter and more pragmatic approach:

  • Extend the existing Webform handler to optionally persist user input into the associated Commerce Order incrementally (e.g. on each step), rather than only on final submission.
  • Introduce a new Webform component that embeds the Commerce checkout payment step via an iframe. The embedded checkout page can be stripped down to render only the payment form (no navigation, no surrounding blocks - perhaps, outside of the scope for this module). This allows the payment step to visually and structurally integrate into the Webform flow. The approach leverages existing Commerce checkout functionality without duplicating payment logic.

We have prototyped this approach and found it to work reliably, including with multiple Stripe payment methods and PayPal.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

spleshka created an issue. See original summary.

spleshka’s picture

Status: Active » Needs review
spleshka’s picture

StatusFileSize
new407.04 KB

Here's an example of how the multi-step flow with embedded payments looks like on my local env:

spleshka’s picture

StatusFileSize
new703.99 KB
spleshka’s picture

Title: Add support for payments within Webform » Support payments within Webform
facine’s picture

Status: Needs review » Needs work

Thanks for the contribution and for exploring this approach.

After reviewing the proposal, I don’t think this solution is the right direction for the project at this stage. While the iframe-based approach may work in some scenarios, it introduces several concerns and limitations:

* What happens if the webform itself is already embedded in an iframe? Nesting iframes could technically work, but it adds complexity and potential fragility that we should avoid.
* How would this behave when mixing different payment flows, especially onsite gateways (e.g. Stripe) with redirect-based ones?
* What would be the impact on the webform submission state? For example, would submissions remain in draft state or transition correctly?
* One of the long-term goals is to move towards a fully webform-driven flow, potentially removing the need for the cart manager and its associated session. An iframe-based solution would not align with that direction.

I believe we should focus on a more robust and extensible solution, even if it requires a more complex and time-consuming implementation.

elaman made their first commit to this issue’s fork.

leo pitt’s picture

Thanks for the patch.
I think that there may be a small issue with this - I receive the following warning:

Warning: Undefined array key "#order_type" in Drupal\commerce_webform_order\Plugin\WebformElement\CheckoutEmbed->prepare() (line 120 of /var/www/html/docroot/modules/contrib/commerce_webform_order/src/Plugin/WebformElement/CheckoutEmbed.php)

Do we need

    if (!isset($element['#order_type'])) {
      return;
    }

in CheckoutEmbed:prepare?