Skip to content

Commit

Permalink
feat: 🥓 fallback anchor link support (HTML-first approach) 🥇 (#5)
Browse files Browse the repository at this point in the history
* feat: fallback link support

* modify throttle rate

* 3.0.0

* feat: customizable button content
  • Loading branch information
murtuzaalisurti authored Jun 7, 2024
1 parent b43c281 commit 2794336
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 36 deletions.
45 changes: 41 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
# <back-to-top>

A `<back-to-top>` button web component with throttle support.
A `<back-to-top>` button web component with throttle support. Fallbacks to anchor link.

```html
<back-to-top throttle="600"></back-to-top>
<back-to-top throttle="600">
<!-- 👇 fallback anchor link (v3.0) -->
<a href="#" style="position: fixed; left: 1rem; bottom: 2rem;">back-to-top</a>
<!-- 👇 insert button content here -->
<template>
button content here
</template>
</back-to-top>
```

```css
Expand Down Expand Up @@ -61,7 +68,30 @@ With the js script in place, just add this component in your HTML.
<back-to-top throttle="600"></back-to-top>
```

You can style this component however you want, here are some styles to start with:
### Fallback Anchor Link (v3.0)

With version 3.0 you can specify a fallback anchor link which is useful when javascript can't execute.

```html
<back-to-top throttle="600">
<!-- 👇 fallback anchor link (v3.0) -->
<a href="#" style="position: fixed; left: 1rem; bottom: 2rem;">back-to-top</a>
</back-to-top>
```

### Customizable Button Content

You can now specify the button content using a template element inside the `back-to-top` component.

```html
<back-to-top throttle="600">
<template>
button content here
</template>
</back-to-top>
```

You can style this component however you want (the `.back-to-top` class is automatically added to the button for you), here are some styles to start with:

```css
.back-to-top {
Expand All @@ -82,7 +112,14 @@ You can style this component however you want, here are some styles to start wit
Introduced in [v2.0](https://www.npmjs.com/package/@murtuzaalisurti/back-to-top/v/2.0.0), you can now use the `throttle` attribute to set a throttle rate for the back-to-top button. The value is in milliseconds.

```html
<back-to-top throttle="800"></back-to-top>
<back-to-top throttle="600">
<!-- 👇 fallback anchor link (v3.0) -->
<a href="#" style="position: fixed; left: 1rem; bottom: 2rem;">back-to-top</a>
<!-- 👇 insert button content here -->
<template>
button content here
</template>
</back-to-top>
```

## Event Throttling
Expand Down
65 changes: 51 additions & 14 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ class BackToTop extends HTMLElement {
super();
this.currentScrollPos = 0;
this.throttleRate = 400; // milliseconds
this.buttonContent = `
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>
</template>
`
}

static get observedAttributes() {
Expand Down Expand Up @@ -43,10 +48,14 @@ class BackToTop extends HTMLElement {
}

get backToTopButton() {
return document.querySelector("back-to-top > button:first-child");
return this.querySelector("button");
}

get svgUpArrow() {
get backToTopLink() {
return this.querySelector("a");
}

get svg() {
return this.backToTopButton.querySelector('svg');
}

Expand All @@ -58,6 +67,22 @@ class BackToTop extends HTMLElement {
this.throttleRate = Number(value);
}

get getButtonContent() {
return this.buttonContent;
}

set setButtonContent(value) {
this.buttonContent = value;
}

parseHTMLFromString(htmlAsString) {
return new DOMParser().parseFromString(htmlAsString, "text/html");
}

templateContent(element) {
return element.querySelector("template")?.content.cloneNode(true);
}

#defaultStyles = {
position: "fixed",
display: "flex",
Expand Down Expand Up @@ -104,9 +129,22 @@ class BackToTop extends HTMLElement {
}

connectedCallback() {
this.backToTopLink && this.backToTopLink.setAttribute("hidden", true);

this.append(document.createElement("button"));
this.backToTopButton.classList.add("back-to-top");
this.backToTopButton.style = this.#hidden;
this.backToTopButton.removeAttribute("hidden");

// setting default button content from a template
this.setButtonContent = this.templateContent(this.parseHTMLFromString(this.buttonContent));

// if the template exists in the user-defined HTML inside the custom element, then
const buttonContent = this.templateContent(this);
if (buttonContent) this.setButtonContent = buttonContent;

// appending the content inside the button
this.backToTopButton.append(this.buttonContent);

this.currentScrollPos =
document.documentElement.scrollTop ||
Expand All @@ -117,18 +155,17 @@ class BackToTop extends HTMLElement {
window.addEventListener("scroll", this.handleThrottle);
this.backToTopButton.addEventListener("click", this.handleClick);

this.backToTopButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>
`;

const currentSVGStyles = this.getComputedStyles(this.svgUpArrow);

if (currentSVGStyles.getPropertyValue("display") === "inline") {
this.svgUpArrow.style.display = "block";
}

if (currentSVGStyles.getPropertyValue("height") === "auto") {
this.svgUpArrow.style.height = "80%";
if (this.svg) {
const currentSVGStyles = this.getComputedStyles(this.svg);
const currentBackToTopButtonStyles = this.getComputedStyles(this.backToTopButton);

if (currentSVGStyles.getPropertyValue("display") === "inline") {
this.svg.style.display = "block";
}

if (currentSVGStyles.getPropertyValue("height") === currentBackToTopButtonStyles.getPropertyValue("height")) {
this.svg.style.height = "70%";
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@murtuzaalisurti/back-to-top",
"version": "2.0.0",
"version": "3.0.0",
"description": "<back-to-top> web component by Murtuzaali Surti",
"type": "module",
"main": "public/main.js",
Expand Down
10 changes: 6 additions & 4 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@
cursor: pointer;
transition: opacity 0.3s ease-in-out, visibility 0.3s ease-in-out;
}
.back-to-top svg {
height: 80%;
}
</style>
</head>

<body style="min-height: 200rem;">
<back-to-top throttle="600"></back-to-top>
<back-to-top throttle="350">
<a href="#" style="position: fixed; left: 1rem; bottom: 2rem;">back-to-top</a>
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>
</template>
</back-to-top>
<script type="module" src="./main.js"></script>
</body>

Expand Down
48 changes: 37 additions & 11 deletions public/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@
}));
this.currentScrollPos = 0;
this.throttleRate = 400;
this.buttonContent = `
<template>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>
</template>
`;
}
static get observedAttributes() {
return ["throttle"];
Expand Down Expand Up @@ -143,9 +148,12 @@
}).join(";").concat(";");
}
get backToTopButton() {
return document.querySelector("back-to-top > button:first-child");
return this.querySelector("button");
}
get backToTopLink() {
return this.querySelector("a");
}
get svgUpArrow() {
get svg() {
return this.backToTopButton.querySelector("svg");
}
get getThrottleRate() {
Expand All @@ -154,6 +162,18 @@
set setThrottleRate(value) {
this.throttleRate = Number(value);
}
get getButtonContent() {
return this.buttonContent;
}
set setButtonContent(value) {
this.buttonContent = value;
}
parseHTMLFromString(htmlAsString) {
return new DOMParser().parseFromString(htmlAsString, "text/html");
}
templateContent(element) {
return element.querySelector("template")?.content.cloneNode(true);
}
getComputedStyles(e) {
return window.getComputedStyle(e, null);
}
Expand All @@ -169,22 +189,28 @@
}, rate);
}
connectedCallback() {
this.backToTopLink && this.backToTopLink.setAttribute("hidden", true);
this.append(document.createElement("button"));
this.backToTopButton.classList.add("back-to-top");
this.backToTopButton.style = __privateGet(this, _hidden);
this.backToTopButton.removeAttribute("hidden");
this.setButtonContent = this.templateContent(this.parseHTMLFromString(this.buttonContent));
const buttonContent = this.templateContent(this);
if (buttonContent) this.setButtonContent = buttonContent;
this.backToTopButton.append(this.buttonContent);
this.currentScrollPos = document.documentElement.scrollTop || window.scrollY || document.body.scrollTop;
this.handleThrottle = this.throttledFunction(this.getThrottleRate);
window.addEventListener("scroll", this.handleThrottle);
this.backToTopButton.addEventListener("click", this.handleClick);
this.backToTopButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>
`;
const currentSVGStyles = this.getComputedStyles(this.svgUpArrow);
if (currentSVGStyles.getPropertyValue("display") === "inline") {
this.svgUpArrow.style.display = "block";
}
if (currentSVGStyles.getPropertyValue("height") === "auto") {
this.svgUpArrow.style.height = "80%";
if (this.svg) {
const currentSVGStyles = this.getComputedStyles(this.svg);
const currentBackToTopButtonStyles = this.getComputedStyles(this.backToTopButton);
if (currentSVGStyles.getPropertyValue("display") === "inline") {
this.svg.style.display = "block";
}
if (currentSVGStyles.getPropertyValue("height") === currentBackToTopButtonStyles.getPropertyValue("height")) {
this.svg.style.height = "70%";
}
}
}
// observing the "throttle" attribute
Expand Down

0 comments on commit 2794336

Please sign in to comment.