<div class="bux-multi-form" id="form-1021185431">
<div class="bux-multi-form__layout">
<div class="bux-multi-form__featured-card">
<div class="bux-panel">
<h2 class="bux-panel__heading">
Sign up to hear from our college.
</h2>
<p>All steps that have been completed are indicated by an outlined circle with a checkmark. The current step the user is on is indicated by a filled circle. Steps the user has not encountered yet, or future steps, are indicated by an outlined circle.</p>
</div>
</div>
<div class="bux-multi-form__form-container bux-multi-form__form-container--featured">
<div class="bux-multi-form__header">
<h2 class="bux-multi-form__title">Indoor space request</h2>
<div class="bux-progress-bar" aria-label="Progress">
<div class="bux-progress-bar__track">
<div class="bux-progress-bar__fill"></div>
</div>
<div class="bux-progress-bar__steps-container">
<div class="bux-progress-bar__step bux-progress-bar__step--current">
<span class="bux-progress-bar__icon">1</span>
</div>
<div class="bux-progress-bar__step bux-progress-bar__step--current">
<span class="bux-progress-bar__icon">2</span>
</div>
<div class="bux-progress-bar__step bux-progress-bar__step--current">
<span class="bux-progress-bar__icon">3</span>
</div>
<div class="bux-progress-bar__success">
<span class="bux-progress-bar__success-icon"></span>
</div>
</div>
</div>
</div>
<form class="bux-multi-form__form">
<div class="bux-multi-form__form-step is-active">
<h3 class="bux-multi-form__form-step-title-container">
<span class="bux-multi-form__form-step-title">Contact info</span>
<span class="bux-multi-form__step-counter"> (Step 1 of 3)<span>
</h3>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-1305939366">
First Name
<span class="bux-text-field__required">
(required)
</span>
</label>
<input id="bux-text-field__text-field-1305939366" class="bux-text-field__input" name="bux-text-field__text-field-1305939366" placeholder="Placeholder Text" required />
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-1456958799">
Last Name
<span class="bux-text-field__required">
(required)
</span>
</label>
<input id="bux-text-field__text-field-1456958799" class="bux-text-field__input" name="bux-text-field__text-field-1456958799" placeholder="Placeholder Text" required />
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-1420327583">
Title
</label>
<input id="bux-text-field__text-field-1420327583" class="bux-text-field__input" name="bux-text-field__text-field-1420327583" placeholder="Placeholder Text" />
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-441746736">
Company
<span class="bux-text-field__required">
(required)
</span>
</label>
<input id="bux-text-field__text-field-441746736" class="bux-text-field__input" name="bux-text-field__text-field-441746736" placeholder="Placeholder Text" required />
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-680916528">
Email
<span class="bux-text-field__required">
(required)
</span>
</label>
<input id="bux-text-field__text-field-680916528" class="bux-text-field__input" name="bux-text-field__text-field-680916528" placeholder="Placeholder Text" required />
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-82427372">
Phone
<span class="bux-text-field__required">
(required)
</span>
</label>
<span class="bux-text-field__helper-text" id="bux-text-field__helper-text-82427372">
Include area code
</span>
<input id="bux-text-field__text-field-82427372" class="bux-text-field__input" name="bux-text-field__text-field-82427372" aria-describedby="bux-text-field__helper-text-82427372" placeholder="555-555-5555" required />
</div>
</div>
</div>
<div class="bux-multi-form__form-step">
<h3 class="bux-multi-form__form-step-title-container">
<span class="bux-multi-form__form-step-title">Event basics</span>
<span class="bux-multi-form__step-counter"> (Step 2 of 3)<span>
</h3>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-1490015209">
Event Name
</label>
<input id="bux-text-field__text-field-1490015209" class="bux-text-field__input" name="bux-text-field__text-field-1490015209" placeholder="Placeholder Text" />
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-selection-dropdown">
<label class="bux-selection-dropdown__label" for="bux-selection-dropdown__selection-dropdown-1248064300">
Choose One
</label>
<div class="bux-selection-dropdown__input">
<select id="bux-selection-dropdown__selection-dropdown-1248064300" name="selection-dropdown-event-type">
<option>Choose One</option>
<option value="Symposium">Symposium</option>
<option value="Lecture">Lecture</option>
<option value="Holiday">Holiday</option>
</select>
</div>
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-1606806170">
Event Start Date
</label>
<input id="bux-text-field__text-field-1606806170" class="bux-text-field__input" name="bux-text-field__text-field-1606806170" placeholder="Placeholder Text" />
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-1250706110">
Event End Date
</label>
<input id="bux-text-field__text-field-1250706110" class="bux-text-field__input" name="bux-text-field__text-field-1250706110" placeholder="Placeholder Text" />
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-radio">
<fieldset id="bux-radio__radio-1121615023" class="bux-radio__fieldset">
<legend class="bux-radio__legend">
Is your date flexible?
</legend>
<div class="bux-radio__input-spacer">
<div class="bux-radio__option">
<input type="radio" id="bux-radio__option-1950978296" name="radio-button-flexible" />
<label for="bux-radio__option-1950978296">Yes</label>
</div>
<div class="bux-radio__option">
<input type="radio" id="bux-radio__option-827560207" name="radio-button-flexible" />
<label for="bux-radio__option-827560207">No</label>
</div>
</div>
</fieldset>
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-1586266167">
Timeframe of Event
</label>
<input id="bux-text-field__text-field-1586266167" class="bux-text-field__input" name="bux-text-field__text-field-1586266167" placeholder="Placeholder Text" />
</div>
</div>
</div>
<div class="bux-multi-form__form-step">
<h3 class="bux-multi-form__form-step-title-container">
<span class="bux-multi-form__form-step-title">Event details</span>
<span class="bux-multi-form__step-counter"> (Step 3 of 3)<span>
</h3>
<div class="bux-multi-form__form-field">
<div class="bux-text-field">
<label class="bux-text-field__label" for="bux-text-field__text-field-965305260">
Total Number of Guests
</label>
<input id="bux-text-field__text-field-965305260" class="bux-text-field__input" name="bux-text-field__text-field-965305260" placeholder="Placeholder Text" />
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-selection-dropdown">
<label class="bux-selection-dropdown__label" for="bux-selection-dropdown__selection-dropdown-566910861">
Choose One
</label>
<div class="bux-selection-dropdown__input">
<select id="bux-selection-dropdown__selection-dropdown-566910861" name="selection-dropdown-room-setup">
<option>Choose One</option>
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
<option value="Option 3">Option 3</option>
</select>
</div>
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-radio">
<fieldset id="bux-radio__radio-75789113" class="bux-radio__fieldset">
<legend class="bux-radio__legend">
Are breakout rooms required?
</legend>
<div class="bux-radio__input-spacer">
<div class="bux-radio__option">
<input type="radio" id="bux-radio__option-265361493" name="radio-button-breakout" />
<label for="bux-radio__option-265361493">Yes</label>
</div>
<div class="bux-radio__option">
<input type="radio" id="bux-radio__option-1772198341" name="radio-button-breakout" />
<label for="bux-radio__option-1772198341">No</label>
</div>
</div>
</fieldset>
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-radio">
<fieldset id="bux-radio__radio-1544240244" class="bux-radio__fieldset">
<legend class="bux-radio__legend">
Is catering required?
</legend>
<div class="bux-radio__input-spacer">
<div class="bux-radio__option">
<input type="radio" id="bux-radio__option-1076985323" name="radio-button-catering" />
<label for="bux-radio__option-1076985323">Yes</label>
</div>
<div class="bux-radio__option">
<input type="radio" id="bux-radio__option-2041555147" name="radio-button-catering" />
<label for="bux-radio__option-2041555147">No</label>
</div>
</div>
</fieldset>
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-radio">
<fieldset id="bux-radio__radio-253003117" class="bux-radio__fieldset">
<legend class="bux-radio__legend">
Will your group require overnight rooms?
</legend>
<div class="bux-radio__input-spacer">
<div class="bux-radio__option">
<input type="radio" id="bux-radio__option-814748556" name="radio-button-overnight" />
<label for="bux-radio__option-814748556">Yes</label>
</div>
<div class="bux-radio__option">
<input type="radio" id="bux-radio__option-8423806" name="radio-button-overnight" />
<label for="bux-radio__option-8423806">No</label>
</div>
</div>
</fieldset>
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-radio">
<fieldset id="bux-radio__radio-260278399" class="bux-radio__fieldset">
<legend class="bux-radio__legend">
Do you have a preferred venue?
</legend>
<div class="bux-radio__input-spacer">
<div class="bux-radio__option">
<input type="radio" id="bux-radio__option-1257823627" name="radio-button-venue" />
<label for="bux-radio__option-1257823627">Yes</label>
</div>
<div class="bux-radio__option">
<input type="radio" id="bux-radio__option-209226642" name="radio-button-venue" />
<label for="bux-radio__option-209226642">No</label>
</div>
</div>
</fieldset>
</div>
</div>
<div class="bux-multi-form__form-field">
<div class="bux-text-area">
<label class="bux-text-area__label" for="bux-text-area__text-area-1759941980">
Additional Comments
</label>
<textarea id="bux-text-area__text-area-1759941980" class="bux-text-area__text-area" name="bux-text-area__text-area-1759941980" placeholder="Placeholder Text"></textarea>
</div>
</div>
</div>
<div class="bux-multi-form__confirmation">
<div class="bux-multi-form__confirmation-content">
<h3 class="bux-multi-form__form-title-container">Form complete</h3>
<div>Thank you for submitting.</div>
</div>
</div>
<div class="bux-multi-form__button-container">
<div class="bux-multi-form__back-button">
<button class="bux-button bux-button--alt">
Back:
</button>
</div>
<div class="bux-multi-form__next-button">
<button class="bux-button">
Next: Event basics
</button>
</div>
</div>
</form>
</div>
</div>
</div>
{#
Multi Step Form
Available variables:
- direction: Either 'vertical' or 'horizontal'.
- steps: Array containing a list of steps for the form.
- step.name: String for the name of the step.
- step.questions: Array containing a list of forms.
- question.field: Machine name of the form field.
- question.context: Array of variables for each field item. See each form item's
documentation for more details.
#}
{% if featured_card_type %}
{% set featured_card_position = featured_card_position|default('left') %}
{% endif %}
{% set featured_card %}
{% if featured_card_type %}
<div class="bux-multi-form__featured-card">
{% if featured_card_type == 'image' %}
{% include '@image' with featured_card_data %}
{% elseif featured_card_type == 'panel' %}
{% include '@panel' with featured_card_data %}
{% elseif featured_card_type == 'text' %}
<div class="bux-multi-form__text">
{{ featured_card_data.text | raw }}
</div>
{% endif %}
</div>
{% endif %}
{% endset %}
<div class="bux-multi-form" id="form-{{ random() }}">
<div class="bux-multi-form__layout">
{% if featured_card_position == 'left' %}
{{ featured_card }}
{% endif %}
<div class="bux-multi-form__form-container{{ featured_card_type ? " bux-multi-form__form-container--featured" : ""}}{{ modifier ? " bux-multi-form__form-container--" ~ modifier : ""}}">
<div class="bux-multi-form__header">
<h2 class="bux-multi-form__title">{{ form_title }}</h2>
{% include '@progress-bar' with modifier %}
</div>
<form class="bux-multi-form__form">
{% for step in steps %}
<div class="bux-multi-form__form-step{{ loop.index == 1 ? " is-active" : ""}}">
<h3 class="bux-multi-form__form-step-title-container">
<span class="bux-multi-form__form-step-title">{{ step.name }}</span>
<span class="bux-multi-form__step-counter"> (Step {{loop.index}} of {{steps|length}})<span>
</h3>
{% for question in step.questions %}
<div class="bux-multi-form__form-field">
{% set form_field = '@' ~ question.field|trim %}
{% include form_field with (question.context ?? {}) %}
</div>
{% endfor %}
</div>
{% endfor %}
<div class="bux-multi-form__confirmation">
<div class="bux-multi-form__confirmation-content">
<h3 class="bux-multi-form__form-title-container">{{ confirmation.subtitle | default('Form complete') }}</h3>
<div>{{ confirmation.text | default('Thank you for submitting.') }}</div>
</div>
</div>
<div class="bux-multi-form__button-container">
<div class="bux-multi-form__back-button">
{% render '@button' with {button_text: 'Back:', modifier: 'alt' } %}
</div>
<div class="bux-multi-form__next-button">
{% render '@button' with {button_text: 'Next: ' ~ steps[1].name} %}
</div>
</div>
</form>
</div>
{% if featured_card_position == 'right' %}
{{ featured_card }}
{% endif %}
</div>
</div>
site_name_prefix: Office of
site_name: Learning Relations Excellence
site_slogan: Additional text or site slogan
address_1: 100 Building Name
address_2: 1 Oval Mall
city: Columbus
state: OH
zip: '43210'
contact_email: email@osu.edu
contact_phone: 614-292-OHIO
contact_tty: 614-688-8605
form_title: Indoor space request
direction: vertical
steps:
- name: Contact info
questions:
- field: text-field
context:
input_label: First Name
required: true
placeholder_text: Placeholder Text
- field: text-field
context:
input_label: Last Name
required: true
placeholder_text: Placeholder Text
- field: text-field
context:
input_label: Title
placeholder_text: Placeholder Text
- field: text-field
context:
input_label: Company
required: true
placeholder_text: Placeholder Text
- field: text-field
context:
input_label: Email
required: true
placeholder_text: Placeholder Text
- field: text-field
context:
input_label: Phone
helper_text: Include area code
required: true
placeholder_text: 555-555-5555
- name: Event basics
questions:
- field: text-field
context:
input_label: Event Name
placeholder_text: Placeholder Text
- field: selection-dropdown
context:
input_label: Type of Event
dropdown_label: Choose One
input_name: selection-dropdown-event-type
items:
- text: Symposium
- text: Lecture
- text: Holiday
- field: text-field
context:
input_label: Event Start Date
placeholder_text: Placeholder Text
- field: text-field
context:
input_label: Event End Date
placeholder_text: Placeholder Text
- field: radio-button
context:
legend: Is your date flexible?
input_name: radio-button-flexible
items:
- text: 'Yes'
- text: 'No'
- field: text-field
context:
input_label: Timeframe of Event
placeholder_text: Placeholder Text
- name: Event details
questions:
- field: text-field
context:
input_label: Total Number of Guests
placeholder_text: Placeholder Text
- field: selection-dropdown
context:
input_label: Room Setup
dropdown_label: Choose One
input_name: selection-dropdown-room-setup
items:
- text: Option 1
- text: Option 2
- text: Option 3
- field: radio-button
context:
legend: Are breakout rooms required?
input_name: radio-button-breakout
items:
- text: 'Yes'
- text: 'No'
- field: radio-button
context:
legend: Is catering required?
input_name: radio-button-catering
items:
- text: 'Yes'
- text: 'No'
- field: radio-button
context:
legend: Will your group require overnight rooms?
input_name: radio-button-overnight
items:
- text: 'Yes'
- text: 'No'
- field: radio-button
context:
legend: Do you have a preferred venue?
input_name: radio-button-venue
items:
- text: 'Yes'
- text: 'No'
- field: text-area
context:
input_label: Additional Comments
placeholder_text: Placeholder Text
featured_card_type: panel
featured_card_data:
panel_title: Sign up to hear from our college.
panel_text: >-
All steps that have been completed are indicated by an outlined circle with
a checkmark. The current step the user is on is indicated by a filled
circle. Steps the user has not encountered yet, or future steps, are
indicated by an outlined circle.
.bux-multi-form {
position: relative;
&__layout {
display: flex;
flex-direction: column;
@media (min-width: $bp-md) {
flex-direction: row;
align-items: flex-start;
}
}
&__header {
position: sticky;
top: 0;
z-index: 99;
padding: $sp-16 0;
margin-bottom: $sp-16;
background-color: inherit;
}
&__featured-card {
flex: 1;
max-width: $bp-md;
@media (min-width: $bp-md) {
position: sticky;
top: $sp-32;
padding-top: 0;
}
}
&__form-container {
position: relative;
flex: 1;
padding: $sp-16 $sp-32 $sp-32;
background-color: $white;
&--featured {
border: none;
@media (min-width: $bp-md) {
border: 2px solid $gray-light-60;
}
}
&--gray {
background-color: $gray-light-90;
}
}
&__title {
margin-bottom: $sp-24;
text-align: center;
}
&__form-step-title-container {
margin-bottom: $sp-32;
color: $gray-dark-80;
font-size: 22px;
}
&__confirmation {
position: absolute;
top: 0;
left: 0;
width: 100%;
display: none;
}
&__form {
position: relative;
display: block;
transition: height 300ms ease-in-out;
}
&__form-step {
position: absolute;
top: 0;
left: 0;
width: 100%;
visibility: hidden;
opacity: 0;
pointer-events: none;
&.is-active {
visibility: visible;
opacity: 1;
pointer-events: auto;
}
}
&__button-container {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
display: flex;
justify-content: space-between;
}
.bux-button {
max-width: 200px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
&[data-step="complete"]::before {
position: relative;
top: 2px;
right: $sp-4;
content: "\f101";
font-family: $icon;
}
}
}
import { createProgressBar } from "../form_subcomponents/progress-bar/progress-bar";
const MULTI_STEP_SELECTORS = {
container: ".bux-multi-form",
formContainer: ".bux-multi-form__form-container",
header: ".bux-multi-form__header",
forms: ".bux-multi-form__form-step",
stepTitle: ".bux-multi-form__form-step-title",
progressBar: ".bux-progress-bar",
buttonContainer: ".bux-multi-form__button-container",
nextButton: ".bux-multi-form__next-button button",
backButton: ".bux-multi-form__back-button button",
confirmation: ".bux-multi-form__confirmation",
iconCurrent: "bux-multi-form__step-icon--current",
iconComplete: "bux-multi-form__step-icon--complete",
horizontal: ".bux-multi-form__layout--horizontal",
vertical: ".bux-multi-form__layout--vertical",
};
export const createMultiStepForm = (container: HTMLElement) => {
const form = container.querySelector<HTMLFormElement>("form") as HTMLFormElement;
const formContainer = container.querySelector<HTMLElement>(MULTI_STEP_SELECTORS.formContainer);
const forms = container.querySelectorAll<HTMLElement>(MULTI_STEP_SELECTORS.forms);
const nextButton = container.querySelector<HTMLButtonElement>(MULTI_STEP_SELECTORS.nextButton);
const backButton = container.querySelector<HTMLButtonElement>(MULTI_STEP_SELECTORS.backButton);
const progressBarElement = container.querySelector<HTMLElement>(MULTI_STEP_SELECTORS.progressBar);
const confirmationContainer = container.querySelector<HTMLElement>(
MULTI_STEP_SELECTORS.confirmation,
);
if (
!form ||
!nextButton ||
!backButton ||
!progressBarElement ||
!formContainer ||
!confirmationContainer ||
forms.length === 0
) {
throw new TypeError(`Buckeye UX Multi-Step Form is missing required elements.`);
}
let currentStep = 0;
let isProcessing = false;
const progressBar = createProgressBar(progressBarElement);
form.setAttribute("novalidate", "true");
const isFormStart = () => currentStep === 0;
const isSubmitStep = () => currentStep === forms.length - 1;
const isConfirmationStep = () => currentStep === forms.length;
const getStepLabel = (forms: NodeListOf<HTMLElement>, index: number): string => {
if (!forms[index]) return "";
return forms[index].querySelector(MULTI_STEP_SELECTORS.stepTitle)?.textContent || "";
};
const focusFirstInput = () => {
const firstInput = forms[currentStep].querySelector<HTMLElement>("input, select, textarea");
if (firstInput) {
firstInput.focus({ preventScroll: true });
}
};
const switchActiveStep = (current: HTMLElement, next: HTMLElement) => {
current.classList.remove("is-active");
next.classList.add("is-active");
};
const updateFormHeight = () => {
requestAnimationFrame(() => {
let activeContentHeight = 0;
if (isConfirmationStep() && confirmationContainer) {
activeContentHeight = confirmationContainer.offsetHeight;
} else {
const activeStepElement = forms[currentStep];
if (activeStepElement) {
activeContentHeight = activeStepElement.offsetHeight;
}
}
const buttonContainer = container.querySelector<HTMLElement>(
MULTI_STEP_SELECTORS.buttonContainer,
);
const buttonHeight = buttonContainer ? buttonContainer.offsetHeight : 0;
const totalHeight = activeContentHeight + buttonHeight;
form.style.height = `${totalHeight}px`;
});
};
const updateBackButton = () => {
if (isFormStart() || isProcessing || isConfirmationStep()) {
backButton.style.display = "none";
return;
}
backButton.style.display = "block";
const backButtonLabel = getStepLabel(forms, currentStep - 1);
backButton.textContent = `Back: ${backButtonLabel}`;
};
const updateNextButton = () => {
if (isProcessing) {
nextButton.textContent = "Processing...";
nextButton.disabled = true;
nextButton.classList.add("bux-button--disabled");
return;
}
nextButton.classList.remove("bux-button--disabled");
nextButton.type = "button";
delete nextButton.dataset.step;
if (isSubmitStep()) {
nextButton.textContent = "Submit";
nextButton.type = "submit";
nextButton.dataset.step = "submit";
return;
}
if (isConfirmationStep()) {
nextButton.textContent = "Complete";
nextButton.type = "reset";
nextButton.dataset.step = "complete";
nextButton.disabled = false;
return;
}
const nextButtonLabel = getStepLabel(forms, currentStep + 1);
nextButton.textContent = `Next: ${nextButtonLabel}`;
};
const updateButtons = () => {
updateBackButton();
updateNextButton();
};
const validateFormStepInputs = (step: number): boolean => {
const inputs = forms[step].querySelectorAll<
HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
>("input, select, textarea");
for (const input of inputs) {
if (!input.checkValidity()) {
input.reportValidity();
return false;
}
}
return true;
};
const sendFormData = () => {
const formData = new FormData(form);
progressBar.complete();
isProcessing = true;
updateButtons();
const submitEvent = new CustomEvent("bux-form:submit", {
bubbles: true,
cancelable: true,
detail: {
formData: formData,
success: () => {
isProcessing = false;
currentStep++;
updateButtons();
showConfirmationView();
},
fail: (errorMessage = "Error") => {
isProcessing = false;
alert(errorMessage);
updateButtons();
},
},
});
const eventWasNotCancelled = container.dispatchEvent(submitEvent);
if (eventWasNotCancelled) {
setTimeout(() => {
const { success } = submitEvent.detail;
success();
}, 1000);
}
};
const updateActiveFormStep = (direction: 1 | -1) => {
const current = forms[currentStep];
const next = forms[currentStep + direction];
if (!current || !next) return;
const currentHeight = current.offsetHeight;
const nextHeight = next.offsetHeight;
if (currentHeight >= nextHeight) {
switchActiveStep(current, next);
} else {
setTimeout(() => switchActiveStep(current, next), 200);
}
};
const handlePageTransition = () => {
setTimeout(() => {
container.scrollIntoView({ behavior: "smooth", block: "start" });
}, 0);
const activeStep = forms[currentStep];
if (!activeStep) return;
focusFirstInput();
};
const showConfirmationView = () => {
for (const formElement of forms) {
formElement.style.display = "none";
}
if (confirmationContainer) {
confirmationContainer.style.display = "block";
updateFormHeight();
container.scrollIntoView({ behavior: "smooth", block: "start" });
const confirmationHeader = confirmationContainer.querySelector<HTMLElement>("h3");
if (confirmationHeader) {
confirmationHeader.setAttribute("tabindex", "-1");
confirmationHeader.focus({ preventScroll: true });
}
}
};
const reset = () => {
form.reset();
progressBar.reset();
currentStep = 0;
isProcessing = false;
if (confirmationContainer) confirmationContainer.style.display = "none";
for (const [index, step] of forms.entries()) {
step.style.display = "";
if (index === 0) {
step.classList.add("is-active");
focusFirstInput();
} else {
step.classList.remove("is-active");
}
}
updateButtons();
updateFormHeight();
progressBar.set(currentStep);
};
const controlForm = (direction: 1 | -1) => {
if (direction === 1 && isConfirmationStep()) {
reset();
return;
}
if (direction === 1 && !validateFormStepInputs(currentStep)) {
return;
}
if (direction === 1 && isSubmitStep()) {
sendFormData();
return;
}
if (
(direction === 1 && !isSubmitStep() && !isConfirmationStep()) ||
(direction === -1 && !isFormStart())
) {
const nextIndex = currentStep + direction;
updateActiveFormStep(direction);
updateFormHeight();
currentStep = nextIndex;
progressBar.set(currentStep);
updateButtons();
handlePageTransition();
}
};
const handleContainerClick = (event: MouseEvent) => {
const target = event.target as HTMLElement;
if (target.closest(MULTI_STEP_SELECTORS.nextButton)) {
event.preventDefault();
controlForm(1);
return;
}
if (target.closest(MULTI_STEP_SELECTORS.backButton)) {
event.preventDefault();
controlForm(-1);
return;
}
};
container.addEventListener("click", handleContainerClick);
backButton.style.display = "none";
const observer = new IntersectionObserver(
(entries, observerInstance) => {
for (const entry of entries) {
if (entry.isIntersecting) {
observerInstance.disconnect();
setTimeout(() => {
progressBar.set(currentStep);
}, 300);
}
}
},
{ threshold: 0.2 },
);
observer.observe(container);
updateFormHeight();
return {
reset,
};
};
export const init = () => {
const multiFormDivs = document.querySelectorAll(MULTI_STEP_SELECTORS.container);
for (const formDiv of multiFormDivs) {
const formId = formDiv.id;
if (formId) {
const container = document.querySelector<HTMLElement>(`#${formId}`);
if (!container) continue;
createMultiStepForm(container);
}
}
};
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
No notes defined.