While I may not be an expert in angular, bootstrap, or stripejs, I have taken the time to thoroughly read through their documentations.
To make bootstrap floating labels function properly, it is necessary for the <input>
and <label>
elements to be direct siblings. This is because the floating label relies on the :placeholder-shown
pseudo element. However, an issue arises when your mounted stripe elements are enclosed within an iframe as opposed to being a standalone input, making it challenging for bootstrap floating labels to work seamlessly without modifications.
In referencing the stripe API documentation that suggests using { labels: 'floating' }
, experimentation reveals that this feature only applies to elements mounted together in a group (such as 'address'), where the label sits within the iframe structure. For individual mounted elements requiring labels, a different method like this one must be employed. Unfortunately, utilizing this method does not integrate the label inside the iframe, impeding the functionality of floating labels from the appearance API.
Despite residing within the iframe, the inputs still possess the ability to trigger class changes outside the iframe (e.g., StripeElement--focus
, StripeElement--complete
, and StripeElement--invalid
). As a workaround, emulating the bootstrap floating label behavior by replicating it in custom code using CSS seems to be a viable solution.
To address this issue, consider adding the following CSS:
...
/* reset the original behavior of the floating labels for #custom-inputs */
#custom-inputs .form-floating > .form-control:focus ~ label,
#custom-inputs .form-floating > .form-control:not(:placeholder-shown) ~ label {
opacity: 1;
transform: scale(1) translateY(0) translateX(0);
}
/* mimic the behavior of bootstrap floating labels for #custom-inputs */
#custom-inputs .form-floating > .form-control.StripeElement--focus ~ label,
#custom-inputs .form-floating > .form-control.StripeElement--complete ~ label,
#custom-inputs .form-floating > .form-control.StripeElement--invalid ~ label {
opacity: 0.8;
transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem);
}
#custom-inputs .StripeElement--focus {
color: #212529;
background-color: #fff;
border-color: #86b7fe;
outline: 0;
box-shadow: 0 0 0 0.25rem rgb(13 110 253 / 25%);
}
...
Additionally, remember to clear out the placeholder text (to utilize the floating labels):
...
if (!this.cardNumber) {
this.cardNumber = this.elements.create('cardNumber', {
...this.emptyOptions,
placeholder: '',
});
this.cardNumber.mount('#floatingNumber');
}
if (!this.cardCvc) {
this.cardCvc = this.elements.create('cardCvc', {
...this.emptyOptions,
placeholder: '',
});
this.cardCvc.mount('#floatingCvc');
}
if (!this.cardExpiry) {
this.cardExpiry = this.elements.create('cardExpiry', {
...this.emptyOptions,
placeholder: '',
});
this.cardExpiry.mount('#floatingExpiry');
}
...
For a demonstration of these alterations, refer to the modified Stackblitz provided here.