i have a two forms, one for sendOTP and the other one for verifyOTP and the verify otp one is taller than the send otp. the height transition for my container is jumpy on getting back from second form to first one.
i've used transition:slide to smoothly change the height, but when i'm going back from second form to first one the slide goes to the height of verify otp form(the taller one) and jump to the height of first form. i've used fly transition as well but same issue persisted, at first i wanted a transition from right to left between forms with fly transition x: -300, x: 300 but not working on height.
this is my code:
<div class="flex overflow-hidden"
transition:slide={{ duration: 500, easing: circInOut }}>
{#if !$showOTPForm}
<div
class="min-w-full"
out:slide={{ duration: 500, easing: circInOut }}
in:slide={{ duration: 500, delay: 500, easing: circInOut }}
>
<SendOtpForm on:success={handleLoginSuccess} />
</div>
{:else if $showOTPForm}
<div
class="min-w-full"
in:slide={{ duration: 500, delay: 500, easing: circInOut }}
out:slide={{ duration: 500, easing: circInOut }}
>
<VerifyOtpForm {phoneNumber} on:back={handleBackToSendOtp} />
</div>
{/if}
</div>
Try the following:
To your Script tag add:
<script>
// bind the height of your two forms
let sendOtpHeight
let verifyOtpHeight
// Reactively switch the height of the container using the same
// condition as the {#if} block
$: containerHeight = !$showOtpForm ? sendOtpHeight : verifyOtpHeight
</scritp>
In the HTML part, bind the client heights of the wrappers and inline the height of the container concatenating the containerHeight
value. Add a transition to the height and it should grow and shrink smoothly.
<div class="flex overflow-hidden"
style="height: {containerHeight}px; transition: height 0.6s ease-in-out"
transition:slide={{ duration: 500, easing: circInOut }}>
{#if !$showOTPForm}
<div
class="min-w-full"
out:slide={{ duration: 500, easing: circInOut }}
in:slide={{ duration: 500, delay: 500, easing: circInOut }}
bind:clientHeight={sendOtpHeight}
>
<SendOtpForm on:success={handleLoginSuccess} />
</div>
{:else if $showOTPForm}
<div
class="min-w-full"
in:slide={{ duration: 500, delay: 500, easing: circInOut }}
out:slide={{ duration: 500, easing: circInOut }}
bind:clientHeight={verifyOtpHeight}
>
<VerifyOtpForm {phoneNumber} on:back={handleBackToSendOtp} />
</div>
{/if}
</div>
The issue may persist because during the switch both wrappers are children of the container. To fix that, add position:relative
to the container and make both wrappers position:absolute; top: 0; left: 0
. Something like this:
<div class="flex overflow-hidden"
style=" height: {containerHeight}px;
transition: height 0.6s ease-in-out;
position:relative;
"
transition:slide={{ duration: 500, easing: circInOut }}>
{#if !$showOTPForm}
<div
class="min-w-full form-wrapper"
out:slide={{ duration: 500, easing: circInOut }}
in:slide={{ duration: 500, delay: 500, easing: circInOut }}
bind:clientHeight={sendOtpHeight}
>
<SendOtpForm on:success={handleLoginSuccess} />
</div>
{:else if $showOTPForm}
<div
class="min-w-full form-wrapper"
in:slide={{ duration: 500, delay: 500, easing: circInOut }}
out:slide={{ duration: 500, easing: circInOut }}
bind:clientHeight={verifyOtpHeight}
>
<VerifyOtpForm {phoneNumber} on:back={handleBackToSendOtp} />
</div>
{/if}
</div>
<style>
.form-wrapper {
position: absolute;
top: 0px;
left: 0px;
}
</style>