Overview
AnchorJS lets you drop deep anchor links (like these) onto any webpage, and be on your way.
You don't need to set up IDs or worry about urls. AnchorJS will respect your IDs if you have them, and generate them if you don't.
It uses an attractive link icon by default, but you can customize the display via options and CSS styling. The examples demonstrate a few customization ideas.
Finally, AnchorJS is lightweight, accessible, and dependency-free.
Installation
Download AnchorJS using npm,
npm install anchor-js
... and then include it in your project:
import AnchorJS from 'anchor-js';
const anchors = new AnchorJS();
anchors.add();
You could also include it in your webpage via a CDN like CDNJS or jsDelivr,
<script src="https://cdn.jsdelivr.net/npm/anchor-js/anchor.min.js"></script>
<script>
anchors.add();
</script>
...or import it globally with ES Modules:
import 'https://cdn.jsdelivr.net/npm/anchor-js/anchor.min.js';
anchors.add();
Basic usage
AnchorJS provides the anchors.add()
method which takes a CSS selector (similar to jQuery) for targeting elements you want to deep-link. Here are some usage examples.
/**
* Example 1
* Add anchors to all h1's on the page
*/
anchors.add('h1');
/**
* Example 2
* Adds anchors to elements that have been assigned the class '.anchored'
*/
anchors.add('.anchored');
/**
* Example 3
* If no selector is provided, it falls back to a default selector of:
* 'h2, h3, h4, h5, h6'
*/
anchors.add();
Don't run it too late!
You need to add anchors to the page early in the page load process if you want browsers to jump to the ID properly.
We recommend you call anchors.add()
before the DOM finishes loading...
<!-- Add anchors before the closing body tag. -->
<script>
anchors.add();
</script>
</body>
...or on DOMContentLoaded:
// Add anchors on DOMContentLoaded
document.addEventListener('DOMContentLoaded', function(event) {
anchors.add();
});
Don't add anchors on later events, like $(document).ready()
or window.onload
as some browsers will attempt to jump to your ID before AnchorJS can add it to the page. For more details, see github issue #69).
Options
You can set a number of options to customize how your anchors look:
For example:
/**
* Example 1
* Add anchors to all h1s, h2s and h3s inside of #post.
* Anchors will be always visible.
*/
anchors.options.visible = 'always';
anchors.add('#post h1, #post h2, #post h3');
/**
* Example 2
* Provide options as an object before adding anchors to the page.
* Adds always-visible ¶ anchors in the left margin of each p tag inside .story
*/
anchors.options = {
placement: 'left',
visible: 'always',
icon: '¶'
};
anchors.add('.story > p');
Advanced usage
Pages with a sticky navbar
Pages with a sticky navbar can sometimes cover the headings you are trying to link to.
To prevent this, you can add a few custom styles using the CSS :target pseudo-selector to add margins to targeted headings. Here's an example:
/**
* Create an invisible pseudo-element and make it the height of the
* sticky navbar so the jump takes you to a location above the link
*/
:target::before {
content: "";
display: block;
margin-top: -80px;
height: 80px;
width: 1px;
}
Alternatively, you could use the newer scroll-margin-top
property (as described in this post):
:target {
scroll-margin-top: 80px;
}
Note: This may not be supported in all browsers. Please check caniuse.com for details.
Pages with changing content
It's common to have pages with changing content, like a page for your most recent blog posts, or a page for all posts with a given tag.
Adding anchors to pages like these can be problematic because the links could break when the content leaves that page. To avoid this issue, use the base
option to ensure these anchors always point to the permalinked url for a post. For example:
// Note: you can often get the permalink url from your site's backend
anchors.options.base = "/2019/1/03/my-post";
anchors.add();
// Anchor url before: "#conclusion"
// Anchor url after: "/2019/1/03/my-post#conclusion"
Generating navigations
AnchorJS doesn't include methods for dynamically generating navigations (like a table of contents or jump nav). This is to keep AnchorJS lightweight and simple for the most common usecases.
However, AnchorJS does expose a list of all anchored elements at anchors.elements
. This way, external code can look up the elements and use them to generate navigations (as shown in this example).
You can also use AnchorJS alongside a static navigation with pre-defined IDs (as is done in this example).
Section IDs
In some cases, you might want to link to existing section IDs instead of the heading element itself. You can instruct AnchorJS to do this with the data-anchor-id
attribute:
<section id="section-1">
<h3 data-anchor-id="section-1">Section 1</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed...</p>
</section>
<!-- ... -->
<script>
anchors.add('h3');
</script>
This allows you to do things like highlight sections when your users jump to them.
Multiple sets of anchors
You can have multiple sets of anchors on one page, each with their own design. To do so, just create your own instances of the AnchorJS object:
var sidebarAnchors = new AnchorJS();
anchors.add('.main h2'); // The default instance.
sidebarAnchors.add('.sidebar h2'); // The new instance.
You can preset your instance with whatever options you like:
var sidebarAnchors = new AnchorJS({
placement: 'left',
icon: '¶'
});
sidebarAnchors.add('.sidebar h2');
Removing anchors
You can remove anchors with the anchors.remove()
or anchors.removeAll()
methods:
/**
* Example 1
* Remove anchors from all h1s on the page.
*/
anchors.remove('h1');
/**
* Example 2
* Remove all anchors from the page.
*/
anchors.removeAll();
Removing anchors with .remove()
should be uncommon. If you simply want anchors on a more selective group, consider using the CSS :not() pseudo-class when you add them, like so:
/**
* Example 2
* Add anchors to all h2s, except for those with a class of "no-anchor".
*/
anchors.add('h2:not(.no-anchor)');
Chaining commands
You can chain commands of add()
and remove()
(since they return a copy of anchors
), but it's usually more performant to lean on CSS when targeting elements:
/**
* Example 1
* Adds anchors to `.my-anchors` and `.my-other-anchors` except for those
* with a class of `no-anchor`.
*/
anchors.add('.my-anchors').add('.my-other-anchors').remove('.no-anchor');
/**
* Example 2
* A more performant way to add anchors to the same classes in Example 1 above.
*/
anchors.add('.my-anchors:not(.no-anchor), .my-other-anchors:not(.no-anchor)');
Examples
Basic Link
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options.visible = 'always';
anchors.add('h3');
Basic Link - Left
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
placement: 'left'
};
anchors.add('h3');
Styled Link
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options.visible = 'always';
anchors.add('h3');
.anchorjs-link {
color: #aaa;
}
.anchorjs-link:hover {
color: #ff5231;
}
Paragraph Link
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
placement: 'left',
icon: '¶'
};
anchors.add('p');
Octothorp
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
icon: '#'
};
anchors.add('h3');
Unicode Icon 1
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
placement: 'left',
icon: '§'
};
anchors.add('h3');
Unicode Icon 2
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
icon: '❡'
};
anchors.add('p');
Custom Text
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
icon: '# LINK'
};
anchors.add('h3');
.anchorjs-link {
font-weight: 200;
margin-left: 1em !important;
padding-right: .375em !important;
padding-left: .375em !important;
font-size: .5em;
border: 1px dashed #ffbaac;
vertical-align: middle;
}
Custom Image
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}// Use an empty string ('') for the icon when styling the background with CSS.
anchors.options = {
visible: 'always',
placement: 'left',
icon: ''
};
anchors.add('h3');
.anchorjs-link {
width: 14px;
height: 32px;
margin-top: 6px;
margin-left: -1.25em !important;
background: url("img/mini-logo.png") no-repeat;
}
Link w/CSS Styling
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
placement: 'left'
};
anchors.add('h3');
.anchorjs-link {
display: inline-block;
height: 32px;
width: 32px;
border-radius: 50%;
background-color: #ff5231;
color: #fff;
margin-top: 4px;
margin-left: -1.4em !important;
padding: 0 !important;
}
.anchorjs-link::after {
position: absolute;
top: -5px;
left: 5px;
}
Icon Font
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}// Just pass in the octal code for your icon-font character.
anchors.options = {
visible: 'always',
icon: '\uF0C1'
};
anchors.add('h3');
.anchorjs-link {
font-family: "your-icon-font";
}
SVG Icon
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
icon: ''
};
anchors.add('h3');
.anchorjs-link {
display: inline-block;
background: url("img/hyperlink.svg") no-repeat;
margin-left: 8px !important;
width: 14px;
height: 24px;
}
Base64 Icon
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
placement: 'left',
icon: ''
};
anchors.add('h3');
.anchorjs-link {
background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIxMCIgdmlld0JveD0iMCAwIDIwIDEwIj48cGF0aCBmaWxsPSIjZmY1MjMxIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNSAwaC0yLjY5NWMuOTM3LjYyNSAxLjgxNiAxLjczOCAyLjA5IDIuNWguNTg1YzEuMjcgMCAyLjUgMS4yNSAyLjUgMi41cy0xLjI3IDIuNS0yLjUgMi41aC0zLjc1QzEwIDcuNSA4LjczIDYuMjUgOC43MyA1YzAtLjQ1LjEzNy0uODc5LjM1Mi0xLjI1SDYuNDA2Yy0uMDk3LjQxLS4xNTYuODItLjE1NiAxLjI1IDAgMi41IDIuNDggNSA0Ljk4IDVIMTVjMi41IDAgNS0yLjUgNS01cy0yLjUtNS01LTV6TTUuNjA1IDcuNUg1LjAyYy0xLjI3IDAtMi41LTEuMjUtMi41LTIuNXMxLjI3LTIuNSAyLjUtMi41aDMuNzVjMS4yMyAwIDIuNSAxLjI1IDIuNSAyLjUgMCAuNDUtLjEzNy44NzktLjM1MiAxLjI1aDIuNjc2Yy4wOTctLjQxLjE1Ni0uODIuMTU2LTEuMjUgMC0yLjUtMi40OC01LTQuOTgtNUg1QzIuNSAwIDAgMi41IDAgNXMyLjUgNSA1IDVoMi42OTVjLS45MzctLjYyNS0xLjgxNi0xLjczOC0yLjA5LTIuNXoiLz48L3N2Zz4=") no-repeat;
margin-top: 15px;
height: 16px;
width: 6px;
margin-left: -1em !important;
}
CSS Icon
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
placement: 'left',
icon: ''
};
anchors.add('h3');
/* See also: nicolasgallagher.com/pure-css-gui-icons */
.anchorjs-link {
border-color: #ff5231 #ff5231 transparent;
border-width: 15px 7px 6px;
border-style: solid;
margin-top: 10px;
font-size: 22px;
padding-right: 0 !important;
padding-left: 0 !important;
margin-left: -1em !important;
}
Emoji
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = {
visible: 'always',
placement: 'left',
icon: '⚓'
};
anchors.add('p');
.anchorjs-link {
margin-left: -2.05em !important;
}
Hover examples
Basic Hover
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.add('h3');
Color Transition
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.add('h3');
.anchorjs-link:hover {
color: #2500ad;
}
*:hover > .anchorjs-link {
transition: color .25s linear;
}
Shift Out
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options.placement = 'left';
anchors.add('h3');
.anchorjs-link {
transition: all .25s linear;
}
*:hover > .anchorjs-link {
margin-left: -1.375em !important;
}
Arrow
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options.icon = '# LINK';
anchors.add('h3');
/* Based on https://codepen.io/corysimmons/pen/NPBXbe */
/* Vendor prefixes not included */
.anchorjs-link {
position: relative;
top: 4px;
height: 36px;
flex: 1;
background-color: #ff5231;
color: #fff;
font-family: Helvetica, Arial, sans-serif;
font-weight: 200;
font-size: 1rem;
margin-right: -6%;
padding-right: 6%;
padding-left: 42px !important;
line-height: 38px;
transition: all .5s ease;
transform: translateX(100%);
}
.anchorjs-link::before {
position: absolute;
display: block;
left: 0;
width: 0;
height: 0;
content: "";
border: 18px solid #fdfdfd; /* Background color */
border-right-color: #ff5231;
transition: all .5s ease;
}
h2 {
display: flex;
}
*:hover > .anchorjs-link {
transform: translateX(0);
}
*:hover > .anchorjs-link:hover {
background: #ff806a;
}
*:hover > .anchorjs-link:hover::before {
border-right-color: #ff806a;
}
Tooltip
Lorem ipsum dolor consectetur amet nulla elit. Vivamus luctus urna sed urna ultricies. Vivamus luctus urna sed.
{}anchors.options = { icon: 'Permalink' };
anchors.add('h3');
/* tooltip box */
.anchorjs-link::after {
display: inline-block;
transition: opacity .25s linear;
font-family: Verdana, sans-serif;
font-size: .75ex;
font-weight: 100;
padding: .5ex 1.5ex;
background-color: #444;
color: #fff;
border-radius: .6ex;
vertical-align: .8ex;
}
/* tooltip arrow */
.anchorjs-link::before {
content: "";
display: inline-block;
border-top: .3ex solid transparent;
border-right: .5ex solid #444;
border-bottom: .3ex solid transparent;
vertical-align: .35ex;
}
.anchorjs-link:hover::after {
background-color: #666;
}
.anchorjs-link:hover::before {
border-right-color: #666;
}