Copied SVG to clipboard
Something went wrong
Copied code to clipboard
Something went wrong
Saved to bookmarks!
Removed from bookmarks
Webflow Challenge: Win $5K

Default

User image

Default

Name

  • -€50
    Upgrade to Lifetime
The Vault/

Back To Top Button

Back To Top Button

Documentation

Webflow

Code

Setup: External Scripts

External Scripts in Webflow

Make sure to always put the External Scripts before the Javascript step of the resource.

In this video you learn where to put these in your Webflow project? Or how to include a paid GSAP Club plugin in your project?

HTML

Copy
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/ScrollTrigger.min.js"></script>

Step 1: Copy structure to Webflow

Copy structure to Webflow

In the video below we described how you can copy + paste the structure of this resource to your Webflow project.

Copy to Webflow

Webflow structure is not required for this resource.

Step 1: Add HTML

HTML

Copy
<div data-back-to-top="wrap" class="back-top__wrap">
  <button data-back-to-top="button" class="back-top__button">
    <div class="back-top__arrow-wrap">
      <div class="back-top__arrow-row">
        <svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 60 60" fill="none" class="back-top__arrow">
          <path d="M47.5 25L30 7.5L12.5 25" stroke="currentColor" stroke-width="6" stroke-miterlimit="10" stroke-linecap="round"></path>
          <path d="M30 7.5L30 55" stroke="currentColor" stroke-width="6" stroke-miterlimit="10" stroke-linecap="round"></path>
        </svg>
      </div>
      <div class="back-top__arrow-row">
        <svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 60 60" fill="none" class="back-top__arrow">
          <path d="M47.5 25L30 7.5L12.5 25" stroke="currentColor" stroke-width="6" stroke-miterlimit="10" stroke-linecap="round"></path>
          <path d="M30 7.5L30 55" stroke="currentColor" stroke-width="6" stroke-miterlimit="10" stroke-linecap="round"></path>
        </svg>
      </div>
    </div>
  </button>
</div>

HTML structure is not required for this resource.

Step 2: Add CSS

CSS

Copy
.back-top__wrap {
  z-index: 100;
  pointer-events: none;
  flex-flow: column;
  justify-content: flex-end;
  align-items: flex-end;
  width: 100%;
  height: 100vh;
  padding: 2em;
  display: flex;
  position: fixed;
  inset: 0%;
}

.back-top__button {
  pointer-events: auto;
  background-color: #fca5a0;
  border: min(.5em, 5px) solid #efeeec;
  border-radius: 1em;
  outline-style: none;
  width: max(5vw, 2.5rem);
  height: max(5vw, 2.5rem);
  padding: .5em;
  position: relative;
}

.back-top__arrow {
  width: 2.5em;
}

.back-top__arrow-wrap {
  flex-flow: column;
  justify-content: flex-start;
  align-items: center;
  width: 100%;
  height: 100%;
  display: flex;
  position: relative;
  overflow: hidden;
}

.back-top__arrow-row {
  flex: none;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  display: flex;
}

/* Hide the back-to-top wrapper on default (to prevent flash on loaded site) */
[data-back-to-top="wrap"]{ opacity: 0;}

.back-top__arrow-row{
  transition: transform 0.5s cubic-bezier(.65, 0, 0, 1);
}

.back-top__button{
  transition: border-width 0.5s cubic-bezier(.65, 0, 0, 1);
}

/* Keyboard focus state */
.back-top__button:focus-visible{
  border-width: 0.6em;
}

.back-top__button:focus-visible .back-top__arrow-row{
  transform: translate(0px, -100%);
}

/* Hover styling */
@media (hover: hover) {
  .back-top__button:hover{
    border-width: 0.6em;
  }

  .back-top__button:hover .back-top__arrow-row{
    transform: translate(0px, -100%);
  }
}

@media screen and (max-width: 991px) {
  .back-top__wrap {
    padding: 1.25em;
  }

  .back-top__button {
    border-radius: .5em;
    padding: .4em;
  }
}

Step 2: Add custom Javascript

Custom Javascript in Webflow

In this video, Ilja gives you some guidance about using JavaScript in Webflow:

Step 2: Add Javascript

Step 3: Add Javascript

Javascript

Copy
gsap.registerPlugin(ScrollTrigger);

function initBackToTop() {
  const buttonWrap = document.querySelector('[data-back-to-top="wrap"]');
  const button = document.querySelector('[data-back-to-top="button"]');
  if (!button || !buttonWrap) return;
  
  // The minimum distance the page must be scrolled (in VH) for the button to appear  
  let minimumScrollDistance = 50;

  // Un-do the initial CSS styling to hide the wrapper
  gsap.set(buttonWrap, { autoAlpha: 1 });
  
  // Hide the button itself
  gsap.set(button,{autoAlpha: 0});

  ScrollTrigger.create({
    trigger: document.body,
    start: `top top-=${minimumScrollDistance}%`,
    onEnter: () => {
      gsap.fromTo(button,{
        autoAlpha: 0,
        rotate:-65,
        scale: 0.4,
      },{
        autoAlpha: 1,
        rotate:0,
        scale: 1,        
        duration: 0.45,
        ease:"power4.out"
      })
    },
    onLeaveBack: () => {
      gsap.to(button,{
        autoAlpha: 0,
        rotate:-65,
        scale: 0.6,
        duration:0.4,
        ease:"power4.out"
      })
    },
  });

  button.addEventListener('click', () => {
    window.scrollTo({ top: 0, behavior: 'smooth' })
  });
}

document.addEventListener("DOMContentLoaded", ()=>{
  initBackToTop();
});

Step 3: Add custom CSS

Step 2: Add custom CSS

Custom CSS in Webflow

Curious about where to put custom CSS in Webflow? Ilja explains it in the below video:

CSS

Copy
/* Hide the back-to-top wrapper on default (to prevent flash on loaded site) */
[data-back-to-top="wrap"]{ opacity: 0;}

/* Show the button in the Webflow environment */
.wf-design-mode [data-back-to-top="wrap"],
.w-editor [data-back-to-top="wrap"]{ opacity: 1; }


.back-top__arrow-row{
  transition: transform 0.5s cubic-bezier(.65, 0, 0, 1);
}

.back-top__button{
  transition: border-width 0.5s cubic-bezier(.65, 0, 0, 1);
}


/* Keyboard focus state */
.back-top__button:focus-visible{
  border-width: 0.6em;
}

.back-top__button:focus-visible .back-top__arrow-row{
  transform: translate(0px, -100%);
}


/* Hover styling */
@media (hover: hover) {
  .back-top__button:hover{
    border-width: 0.6em;
  }

  .back-top__button:hover .back-top__arrow-row{
    transform: translate(0px, -100%);
  }
}

Documentation

This structure basically requires 2 elements on your page:

  • A fixed wrapper (with pointer-events: none) and an attribute of data-back-to-top="wrap"
  • A button inside (with pointer-events: auto) and an attribute of data-back-to-top="button"

The fixed wrapper needs a high z-index to sit on top of everything else. We must ignore the pointer events on the wrapper, otherwise nothing on your page will be clickable.

Change scroll offset

There's a variable called minimumScrollDistance in the function. This decides how many % of the viewport a user must scroll before the button appears. For example, if you want it to appear only after scrolling for a full viewport (100vh) change the value to 100.

Scroll options

In our JS above we use a VanillaJS window.scrollTo method. Below is 2 alternatives in case you're using Lenis or Locomotive scroll. You'll only have to replace the click listener on the button from our main code snippet into the below versions:

Lenis

Explore more options for this method in the official Lenis documentation.

button.addEventListener('click', () => {
  lenis.scrollTo(0, { lerp: 0.1 });
});

Locomotive Scroll

Explore more options for this method in the official Locomotive V5 documentation.

button.addEventListener('click', () => {
  locomotiveScroll.scrollTo(0, { lerp: 0.1 });
});

Resource Details

Code
Scrolling
Scrolltrigger
Javascript
Locomotive
Lenis
VanillaJS

Original source

Ilja van Eck

Creator Credits

We always strive to credit creators as accurately as possible. While similar concepts might appear online, we aim to provide proper and respectful attribution.