<print-link-list><print-link-list> generates a numbered, deduplicated list of links and citations for printed web pages. It is a modern Web Component interpretation of “Improving Link Display for Print”.
The component leaves source content intact, inserts markers that appear only in print, and renders the corresponding destination list where the component is placed.
npm install @aarongustafson/print-link-list
Import the package to define <print-link-list> automatically:
import '@aarongustafson/print-link-list';
Or control registration yourself:
import {
PrintLinkListElement,
definePrintLinkList,
} from '@aarongustafson/print-link-list';
definePrintLinkList();
To register the class under another valid custom-element name, import the side-effect-free implementation directly:
import { PrintLinkListElement } from '@aarongustafson/print-link-list/print-link-list.js';
customElements.define('my-print-links', PrintLinkListElement);
By default, the component inspects the first <main> element.
<main>
<p>
Read the
<a href="https://example.com/guide">complete guide</a>.
</p>
</main>
<print-link-list></print-link-list>
In print, the link receives a superscript marker and the component becomes:
Links
1. https://example.com/guide
Place the component wherever the destination list should appear in the printed document.
target accepts any valid CSS selector and uses its first match.
<article class="printable">
<!-- Content -->
</article>
<print-link-list
target="article.printable"
heading="References"
label-source="Source"
></print-link-list>
An invalid or unmatched selector does not throw. It dispatches print-link-list:error and logs a warning prefixed with <print-link-list> - .
The component:
cite attributes;Source label;javascript: URLs, unsupported schemes, and empty or malformed values;mailto: links into email addresses without query parameters;tel: links into telephone numbers without the scheme; andmailto:, tel:, and download destinations only when the visible link text does not already communicate the destination.Add data-print-link-list-ignore to a reference or any ancestor subtree:
<nav data-print-link-list-ignore>
<a href="/account">Account</a>
</nav>
The component observes its target. Added, removed, or changed links and citations automatically produce an updated, correctly numbered list. Updates are batched to one rebuild per animation frame.
Call refresh() to request an immediate rebuild:
const list = document.querySelector('print-link-list');
const processed = list.refresh();
refresh() returns true when its target was found and processed, or false after a target error.
| Attribute | Property | Default | Description |
|---|---|---|---|
target |
target |
main |
Selector for the first content element to inspect |
heading |
heading |
Links |
Heading above the printed destination list |
label-source |
labelSource |
Source |
Label before each citation superscript |
Setting any property to null or undefined removes its attribute and restores the default.
Translate the citation label directly in markup:
<print-link-list label-source="Quelle"></print-link-list>
Both events bubble and cross shadow boundaries.
print-link-list:updateFires after a successful rebuild:
list.addEventListener('print-link-list:update', (event) => {
console.log(event.detail);
// { destinations: 3, references: 5 }
});
print-link-list:errorFires when target is invalid or has no match:
list.addEventListener('print-link-list:error', (event) => {
console.log(event.detail);
// {
// type: "target-not-found",
// selector: ".missing",
// message: "The target selector \".missing\" did not match an element."
// }
});
type is either invalid-target or target-not-found.
The component has an open shadow root. Its list can be styled with parts:
print-link-list::part(heading) {
font-family: sans-serif;
}
print-link-list::part(list) {
font-size: 9pt;
}
print-link-list::part(item) {
margin-block: 0.25em;
}
print-link-list::part(destination) {
text-decoration: underline;
}
Available custom properties:
| Property | Set on | Default | Description |
|---|---|---|---|
--print-link-list-marker-gap |
Target or an ancestor of its references | 0.15em |
Space before a printed reference marker |
--print-link-list-marker-font-size |
Target or an ancestor of its references | 0.75em |
Printed reference marker size |
--print-link-list-margin |
<print-link-list> |
2rem |
Space before the printed destination list |
Markers live in the target's light DOM, so marker properties inherit from the target/reference context rather than from the component:
article.printable {
--print-link-list-marker-gap: 0.25em;
--print-link-list-marker-font-size: 0.85em;
}
print-link-list {
--print-link-list-margin: 1rem;
}
Markers and the component are hidden on screen by default. Author styles can override these defaults if a screen preview is needed.
aria-hidden and hidden outside print.Without JavaScript, the source document remains readable, but a deduplicated list cannot be generated. A print stylesheet can provide the simpler inline-URL fallback from the original technique:
@media print {
a[href^='http']::after {
content: ' (' attr(href) ')';
font-size: 90%;
}
}
Only use that fallback when the component script is unavailable; otherwise it duplicates destinations. An application can add its own root class before loading modules if it needs to switch between fallback and enhanced styles.
The component requires:
MutationObserverIt is tested in a DOM environment and should be checked in real browser print preview because pagination and print rendering cannot be fully simulated by DOM unit tests.
npm install
npm run test:run
npm run lint
MIT © Aaron Gustafson