Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
October 25, 2021 05:51 am GMT

Svelte multi step form apps

Today we are going to make a multistep form app with Svelte. So let's start.

First, let's make a basic template with Start and Prev buttons:

<main>  <div class="container">    <div class="step-button">      <button class="btn">Prev</button>      <button class="btn">Next</button>    </div>  </div></main><style>  @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');  * {    box-sizing: border-box;  }  main {    font-family: 'Muli', sans-serif;    display: flex;    align-items: center;    justify-content: center;    height: 100vh;    overflow: hidden;    margin: 0;  }  .btn {    background-color: #3498db;    color: #fff;    border: 0;    border-radius: 6px;    cursor: pointer;    font-family: inherit;    padding: 8px 30px;    margin: 5px;    font-size: 14px;  }  .btn:active {    transform: scale(0.98);  }  .btn:focus {    outline: 0;  }  .btn:disabled {    background-color: #e0e0e0;    cursor: not-allowed;  }  .step-button{    margin-top: 1rem;    text-align: center;  }</style>

Handle Button

Now we are going to build a steps progress bar component, So first create this ProgressBar.svelte component:

<script>  export let steps = ['Info', 'Address', 'Payment', 'Confirmation'];</script><div class="progress-container">  <div class="progress"></div>  {#each steps as step, i}    <div class="circle {i == 0 ? 'active' : ''}" data-title={step} >{i+1}</div>  {/each}</div><style>  .progress-container {    display: flex;    justify-content: space-between;    position: relative;    margin-bottom: 30px;    max-width: 100%;    width: 350px;  }  .progress-container::before {    content: '';    background-color: #e0e0e0;    position: absolute;    top: 50%;    left: 0;    transform: translateY(-50%);    height: 4px;    width: 100%;    z-index: -1;  }  .progress {    background-color: #3498db;    position: absolute;    top: 50%;    left: 0;    transform: translateY(-50%);    height: 4px;    width: 0%;    z-index: -1;    transition: 0.4s ease;  }  .circle {    background-color: #fff;    color: #999;    border-radius: 50%;    height: 30px;    width: 30px;    display: flex;    align-items: center;    justify-content: center;    border: 3px solid #e0e0e0;    transition: 0.4s ease;    cursor: pointer;  }  .circle::after{    content: attr(data-title) " ";    position: absolute;    bottom: 35px;    color: #999;    transition: 0.4s ease;  }  .circle.active::after {    color: #3498db;  }  .circle.active {    border-color: #3498db;  }  </style>

Progress Bar

Our progress bar UI is ready, Now we need to implement functionality for the Step panel and Prev, Next button.
The Prev button should be disabled for the first step Info and the Next button should be disabled for the last step Confirmation. So need to track the current active step currentActive and also for the handling progress we write a function handleProgress and for update the progress bar steps add a function update and declare circles for reference all steps elements and progress for progress bar element. So our latest ProgressBar.svelte version like this:

<script>  export let steps = [], currentActive = 1;  let circles, progress;  export const handleProgress = (stepIncrement) => {    circles = document.querySelectorAll('.circle');    if(stepIncrement == 1){      currentActive++      if(currentActive > circles.length) {          currentActive = circles.length      }    } else {      currentActive--      if(currentActive < 1) {          currentActive = 1      }    }    update()  }  function update() {    circles.forEach((circle, idx) => {        if(idx < currentActive) {            circle.classList.add('active')        } else {            circle.classList.remove('active')        }    })    const actives = document.querySelectorAll('.active');    progress.style.width = (actives.length - 1) / (circles.length - 1) * 100 + '%';  }</script><div class="progress-container" bind:this={circles}>  <div class="progress" bind:this={progress}></div>  {#each steps as step, i}    <div class="circle {i == 0 ? 'active' : ''}" data-title={step} >{i+1}</div>  {/each}</div>

And update App.svelte:

<script>let steps = ['Info', 'Address', 'Payment', 'Confirmation'], currentActive = 1, progressBar;const handleProgress = (stepIncrement) => {  progressBar.handleProgress(stepIncrement)}</script><ProgressBar {steps} bind:currentActive bind:this={progressBar}/><button class="btn" on:click={() => handleProgress(-1)} disabled={currentActive == 1}>Prev</button><button class="btn" on:click={() => handleProgress(+1)} disabled={currentActive == steps.length}>Next</button>

Progress Bar working

Now we are going to make Form.svelte component, first, make an input component for reusability InputField.svelte.

<script>  export let value, label, type = 'text';  function typeAction(node){    node.type = type;  }</script><p class="form-control">  {#if label}    <label class="label" for>{label}:</label>  {/if}  <input use:typeAction class="input" bind:value={value}/></p><style>  .form-control{    margin: .5rem 0;    text-align: left;  }  .input{    width: 100%;    display: block;    padding: 0.5rem 0;    margin-top: 0.5rem;    border-width: 1px;    border-radius: 0.25rem;  }</style>

Here we see a new directive use:typeAction its use for set dynamic input type. Ok InputField is ready now move to Form.svelte:

<script>  import InputField from './InputField.svelte';  export let active_step;  let formData = {    name: '',    surname: '',    email: '',    password: '',    address: '',    city: '',    country: '',    postcode: '',    account_name: '',    card_no: ''  }  const handleSubmit = () => {    console.log("Your form data => ",formData)  }</script><form class="form-container" on:submit={handleSubmit}>  {#if active_step == 'Info'}    <InputField label={'Name'} bind:value={formData.name}/>    <InputField label={'Surname'} bind:value={formData.surname}/>    <InputField label={'Email'} bind:value={formData.email}/>    <InputField type={'password'} label={'Password'} bind:value={formData.password}/>  {:else if active_step == 'Address'}    <InputField label={'Address'} bind:value={formData.address}/>    <InputField label={'City'} bind:value={formData.city}/>    <InputField label={'Country'} bind:value={formData.country}/>    <InputField label={'Postcode'} bind:value={formData.postcode}/>  {:else if active_step == 'Payment'}    <InputField label={'Account Name'} bind:value={formData.account_name}/>    <InputField label={'Card No'} bind:value={formData.card_no}/>  {:else if active_step == 'Confirmation'}    <div class="message">      <h2>Thank you for choosing us</h2>      <button class="btn submit">Finish </button>    </div>  {/if}</form><style>.form-container {  background-color: #fff;  border-radius: 10px;  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1), 0 6px 6px rgba(0, 0, 0, 0.1);  padding: 50px 20px;  text-align: center;  max-width: 100%;  width: 350px;}.btn{  color: white;  padding: 0.5rem 0;  margin-top: 0.5rem;  display: inline-block;  width: 100%;  border-radius: 0.25rem;  cursor:pointer;}.submit{  background:linear-gradient(to bottom, #44c767 5%, #50b01c 100%);  background-color:#44c767;}.submit:hover {  background:linear-gradient(to bottom, #50b01c 5%, #44c767 100%);  background-color:#50b01c;}.message{  text-align: center;}</style>

And update App.svelte:

<script>  import Form from './Form.svelte';  import ProgressBar from './ProgressBar.svelte';  let steps = ['Info', 'Address', 'Payment', 'Confirmation'], currentActive = 1, progressBar;  const handleProgress = (stepIncrement) => {    progressBar.handleProgress(stepIncrement)  }</script><main>  <div class="container">    <ProgressBar {steps} bind:currentActive bind:this={progressBar}/>    <Form active_step={steps[currentActive-1]}/>    <div class="step-button">      <button class="btn" on:click={() => handleProgress(-1)} disabled={currentActive == 1}>Prev</button>      <button class="btn" on:click={() => handleProgress(+1)} disabled={currentActive == steps.length}>Next</button>    </div>  </div></main>

Here is the final output:

Image description

Svelte Expanding Card

Full source code in this repl.

You find me in Github.


Original Link: https://dev.to/msisaifu/svelte-multi-step-form-apps-1468

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To