<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.
  • Content:
    .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;
        }
      }
    }
    
  • URL: /components/raw/multi-step-form/_multi-step-form.scss
  • Filesystem Path: src/components/forms/multi-step-form/_multi-step-form.scss
  • Size: 1.9 KB
  • Content:
    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();
    }
    
  • URL: /components/raw/multi-step-form/multi-step-form.ts
  • Filesystem Path: src/components/forms/multi-step-form/multi-step-form.ts
  • Size: 9.8 KB

No notes defined.