Blog
Floating Social Share Buttons with HTML, CSS, and JavaScript
Quick answer: A floating social share toolbar keeps page-sharing actions near readers as they browse. This accessible example uses regular links for X, LinkedIn, Pinterest, and email, with JavaScript for the expandable toolbar, native sharing, and copy-link controls.
In this tutorial, you will build a responsive share dock that works with keyboard controls and screen readers. It does not need Font Awesome, jQuery, or a third-party sharing plugin. The demo reads the current page title and URL, so you can reuse the pattern on other pages.
What you will build
- A floating toggle with an accessible expanded state.
- Share links that include the current page URL and title.
- Native device sharing and a copy-link action when supported.
- A mobile layout, visible keyboard focus, and reduced-motion support.
How the floating share toolbar works
The HTML uses a labeled button to open a navigation list. Each social destination is a real anchor, so the standard share URL still works without JavaScript. JavaScript builds those URLs from window.location.href and document.title, then controls the menu and optional browser APIs.
Use a share toolbar when sharing is a useful next action for your readers. Keep it compact, avoid covering the article, and offer labeled controls. Social network names and share endpoints can change, so review the destinations periodically.
Step 1: Add the HTML structure
Place the toolbar near the end of the page body so it is available across the article. The button controls the navigation with aria-controls and reports its state with aria-expanded. Hidden text gives icon-only links meaningful names to assistive technology.
Step 2: Style the dock for desktop and mobile
The CSS pins the dock near the right edge on larger screens and moves it to the bottom corner on narrow screens. Focus rings remain visible, colors have strong contrast, and the motion is reduced when a visitor requests reduced motion.
Step 3: Build share links and add interactions
Encode the title and page URL before placing them in query strings. The native share API and clipboard API are optional enhancements; both need a secure context such as HTTPS. Provide a helpful fallback when a browser does not support them.
Try the interactive demo
Open the share button, choose a service, or test the copy-link control. On a device that supports the Web Share API, the device sharing menu is available too.
Customize the buttons
- Change the services: Add or remove an anchor and its corresponding share URL builder.
- Change placement: Adjust the
top,right, and mobilebottomrules. - Change the colors: Edit the service-specific background classes while keeping text and focus contrast clear.
- Use your own icon set: Replace the text symbols with inline SVGs and keep a screen-reader label on every control.
Accessibility and implementation notes
Do not use hover as the only way to open the menu. This example uses a button that works by keyboard and touch, closes with Escape, and gives screen readers an updated expanded state. External share pages open with rel="noopener noreferrer". The copy and native share actions fail gracefully when browser permissions or support are unavailable.
Troubleshooting
The copy button does not work
Clipboard access generally requires HTTPS or localhost and can be restricted by browser settings. Serve the project securely and keep the fallback message visible.
The native share button is missing on my device
The Web Share API is not supported in every browser. Keep the individual social and email links available so visitors can still share the page.
The share URL has the wrong page title
Update the document title in the page metadata. The demo uses the browser title at runtime, so the share text follows that value.
Frequently asked questions
Can I use these floating social share buttons without a plugin?
Yes. The example uses plain HTML, CSS, and JavaScript and does not load a social sharing library.
Does this code share automatically when the page opens?
No. It opens a sharing destination only after a visitor selects a share option. This avoids unexpected pop-ups and gives visitors control.
Can I use the toolbar on mobile?
Yes. The layout moves to the bottom corner on small screens, and the controls are large enough for touch input. Check that it does not cover your site’s cookie notice or other fixed controls.
Download the complete example
The ZIP contains the page markup, stylesheet, JavaScript, and setup notes. Update the services and colors to fit your site, then test the toolbar with a keyboard and on a small screen before publishing it.
Interactive floating share toolbar
Open the Share button to try the links. Each destination uses this page's title and address. Native sharing and copying are available when your browser supports them.
const toggleButton = document.querySelector(".share-toggle");
const options = document.querySelector("#share-options");
const statusMessage = document.querySelector(".share-status");
function currentPageDetails() {
return { url: window.location.href, title: document.title };
}
function updateShareLinks() {
const { url, title } = currentPageDetails();
const pageUrl = encodeURIComponent(url);
const pageTitle = encodeURIComponent(title);
document.querySelector('[data-share="x"]').href =
"https://twitter.com/intent/tweet?url=" + pageUrl + "&text=" + pageTitle;
document.querySelector('[data-share="linkedin"]').href =
"https://www.linkedin.com/sharing/share-offsite/?url=" + pageUrl;
document.querySelector('[data-share="pinterest"]').href =
"https://pinterest.com/pin/create/button/?url=" + pageUrl + "&description=" + pageTitle;
document.querySelector('[data-share="email"]').href =
"mailto:?subject=" + pageTitle + "&body=" + encodeURIComponent(title + "\n" + url);
}
function setOpen(isOpen) {
toggleButton.setAttribute("aria-expanded", String(isOpen));
toggleButton.setAttribute("aria-label", isOpen ? "Close sharing options" : "Open sharing options");
options.hidden = !isOpen;
if (isOpen) options.querySelector("a, button")?.focus();
else toggleButton.focus();
}
toggleButton.addEventListener("click", () => {
setOpen(toggleButton.getAttribute("aria-expanded") !== "true");
});
document.addEventListener("keydown", (event) => {
if (event.key === "Escape" && toggleButton.getAttribute("aria-expanded") === "true") setOpen(false);
});
document.querySelector('[data-share="native"]').addEventListener("click", async () => {
const { url, title } = currentPageDetails();
if (!navigator.share) {
statusMessage.textContent = "Device sharing is not supported here. Choose a service or copy the link.";
return;
}
try {
await navigator.share({ title, url });
statusMessage.textContent = "Share menu opened.";
} catch (error) {
if (error.name !== "AbortError") statusMessage.textContent = "Could not open the share menu.";
}
});
document.querySelector('[data-share="copy"]').addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(window.location.href);
statusMessage.textContent = "Link copied to clipboard.";
} catch {
statusMessage.textContent = "Clipboard access is unavailable. Copy the page address from your browser.";
}
});
updateShareLinks();
:root {
font-family: system-ui, sans-serif;
color: #182338;
background: #f3f6fb;
}
* { box-sizing: border-box; }
body { margin: 0; min-width: 320px; }
.share-dock {
position: fixed;
z-index: 5;
top: 50%;
right: max(16px, calc((100vw - 1100px) / 2));
display: grid;
gap: 10px;
transform: translateY(-50%);
}
.share-toggle, .share-link {
display: grid;
width: 52px;
height: 52px;
place-items: center;
border: 0;
border-radius: 50%;
color: #fff;
text-decoration: none;
cursor: pointer;
box-shadow: 0 8px 22px rgb(27 45 88 / 18%);
}
.share-toggle { width: 60px; height: 60px; background: #315eea; }
.share-options {
display: grid;
gap: 9px;
justify-items: center;
padding: 10px 6px;
border: 1px solid #e6ebf4;
border-radius: 28px;
background: #fff;
}
.share-options[hidden] { display: none; }
.share-link:focus-visible, .share-toggle:focus-visible {
outline: 3px solid #172554;
outline-offset: 3px;
}
.share-x { background: #16181d; }
.share-linkedin { background: #0a66c2; }
.share-pinterest { background: #bd081c; }
.share-email { background: #526ee6; }
.share-native { background: #129b8b; }
.share-copy { background: #6f47cf; }
@media (max-width: 600px) {
.share-dock { top: auto; right: 14px; bottom: 16px; transform: none; }
.share-options { grid-template-columns: repeat(3, 44px); }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { transition-duration: .01ms !important; }
}
<aside class="share-dock" aria-label="Share this page">
<button class="share-toggle" type="button" aria-expanded="false"
aria-controls="share-options" aria-label="Open sharing options">
<span aria-hidden="true">↗</span>
<span class="toggle-label">Share</span>
</button>
<nav class="share-options" id="share-options"
aria-label="Sharing options" hidden>
<a class="share-link share-x" data-share="x" target="_blank"
rel="noopener noreferrer" aria-label="Share on X">𝕏</a>
<a class="share-link share-linkedin" data-share="linkedin" target="_blank"
rel="noopener noreferrer" aria-label="Share on LinkedIn">in</a>
<a class="share-link share-pinterest" data-share="pinterest" target="_blank"
rel="noopener noreferrer" aria-label="Share on Pinterest">P</a>
<a class="share-link share-email" data-share="email"
aria-label="Share by email">Email</a>
<button class="share-link share-native" type="button" data-share="native"
aria-label="Share using your device">↗</button>
<button class="share-link share-copy" type="button" data-share="copy"
aria-label="Copy page link">Copy</button>
</nav>
<p class="share-status" role="status" aria-live="polite"></p>
</aside>