<div class="bux-multi-form" id="form-356739289">
    <div class="bux-multi-form__layout">
        <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-485715186">
                                First Name

                                <span class="bux-text-field__required">
                                    (required)
                                </span>
                            </label>

                            <input id="bux-text-field__text-field-485715186" class="bux-text-field__input" name="bux-text-field__text-field-485715186" 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-1274861700">
                                Last Name

                                <span class="bux-text-field__required">
                                    (required)
                                </span>
                            </label>

                            <input id="bux-text-field__text-field-1274861700" class="bux-text-field__input" name="bux-text-field__text-field-1274861700" 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-1731275360">
                                Title
                            </label>

                            <input id="bux-text-field__text-field-1731275360" class="bux-text-field__input" name="bux-text-field__text-field-1731275360" 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-1168779986">
                                Company

                                <span class="bux-text-field__required">
                                    (required)
                                </span>
                            </label>

                            <input id="bux-text-field__text-field-1168779986" class="bux-text-field__input" name="bux-text-field__text-field-1168779986" 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-1470420202">
                                Email

                                <span class="bux-text-field__required">
                                    (required)
                                </span>
                            </label>

                            <input id="bux-text-field__text-field-1470420202" class="bux-text-field__input" name="bux-text-field__text-field-1470420202" 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-729001074">
                                Phone

                                <span class="bux-text-field__required">
                                    (required)
                                </span>
                            </label>

                            <span class="bux-text-field__helper-text" id="bux-text-field__helper-text-729001074">
                                Include area code
                            </span>

                            <input id="bux-text-field__text-field-729001074" class="bux-text-field__input" name="bux-text-field__text-field-729001074" aria-describedby="bux-text-field__helper-text-729001074" 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-1445679957">
                                Event Name
                            </label>

                            <input id="bux-text-field__text-field-1445679957" class="bux-text-field__input" name="bux-text-field__text-field-1445679957" 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-537821882">
                                Choose One
                            </label>

                            <div class="bux-selection-dropdown__input">
                                <select id="bux-selection-dropdown__selection-dropdown-537821882" 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-1463005506">
                                Event Start Date
                            </label>

                            <input id="bux-text-field__text-field-1463005506" class="bux-text-field__input" name="bux-text-field__text-field-1463005506" 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-1778539066">
                                Event End Date
                            </label>

                            <input id="bux-text-field__text-field-1778539066" class="bux-text-field__input" name="bux-text-field__text-field-1778539066" placeholder="Placeholder Text" />

                        </div>
                    </div>
                    <div class="bux-multi-form__form-field">

                        <div class="bux-radio">
                            <fieldset id="bux-radio__radio-1502702025" 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-500548188" name="radio-button-flexible" />
                                        <label for="bux-radio__option-500548188">Yes</label>
                                    </div>

                                    <div class="bux-radio__option">
                                        <input type="radio" id="bux-radio__option-131058055" name="radio-button-flexible" />
                                        <label for="bux-radio__option-131058055">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-661897850">
                                Timeframe of Event
                            </label>

                            <input id="bux-text-field__text-field-661897850" class="bux-text-field__input" name="bux-text-field__text-field-661897850" 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-1572302330">
                                Total Number of Guests
                            </label>

                            <input id="bux-text-field__text-field-1572302330" class="bux-text-field__input" name="bux-text-field__text-field-1572302330" 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-493932751">
                                Choose One
                            </label>

                            <div class="bux-selection-dropdown__input">
                                <select id="bux-selection-dropdown__selection-dropdown-493932751" 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-1813784409" 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-2007891213" name="radio-button-breakout" />
                                        <label for="bux-radio__option-2007891213">Yes</label>
                                    </div>

                                    <div class="bux-radio__option">
                                        <input type="radio" id="bux-radio__option-980714563" name="radio-button-breakout" />
                                        <label for="bux-radio__option-980714563">No</label>
                                    </div>
                                </div>
                            </fieldset>
                        </div>
                    </div>
                    <div class="bux-multi-form__form-field">

                        <div class="bux-radio">
                            <fieldset id="bux-radio__radio-721118670" 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-1691630824" name="radio-button-catering" />
                                        <label for="bux-radio__option-1691630824">Yes</label>
                                    </div>

                                    <div class="bux-radio__option">
                                        <input type="radio" id="bux-radio__option-1049025761" name="radio-button-catering" />
                                        <label for="bux-radio__option-1049025761">No</label>
                                    </div>
                                </div>
                            </fieldset>
                        </div>
                    </div>
                    <div class="bux-multi-form__form-field">

                        <div class="bux-radio">
                            <fieldset id="bux-radio__radio-388172442" 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-2065296805" name="radio-button-overnight" />
                                        <label for="bux-radio__option-2065296805">Yes</label>
                                    </div>

                                    <div class="bux-radio__option">
                                        <input type="radio" id="bux-radio__option-1891756857" name="radio-button-overnight" />
                                        <label for="bux-radio__option-1891756857">No</label>
                                    </div>
                                </div>
                            </fieldset>
                        </div>
                    </div>
                    <div class="bux-multi-form__form-field">

                        <div class="bux-radio">
                            <fieldset id="bux-radio__radio-536178728" 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-198240457" name="radio-button-venue" />
                                        <label for="bux-radio__option-198240457">Yes</label>
                                    </div>

                                    <div class="bux-radio__option">
                                        <input type="radio" id="bux-radio__option-1428030594" name="radio-button-venue" />
                                        <label for="bux-radio__option-1428030594">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-572121081">
                                Additional Comments
                            </label>
                            <textarea id="bux-text-area__text-area-572121081" class="bux-text-area__text-area" name="bux-text-area__text-area-572121081" 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 class="bux-multi-form__featured-card">

            <img class="bux-image" src="/images/placeholders/osu-bux-5.webp" alt="Image placeholder." />

        </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: image
featured_card_position: right
featured_card_data:
  image_url: /images/placeholders/osu-bux-5.webp
  image_alt_text: Image placeholder.
  • 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.