<print-link-list>

npm version Build Status

<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.

Demo

Live Demo (source)

Installation

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);

Basic usage

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.

Custom target and heading

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> - .

Reference rules

The component:

Opting out

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>

Dynamic content

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.

Attributes and properties

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>

Events

Both events bubble and cross shadow boundaries.

print-link-list:update

Fires after a successful rebuild:

list.addEventListener('print-link-list:update', (event) => {
	console.log(event.detail);
	// { destinations: 3, references: 5 }
});

print-link-list:error

Fires 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.

Styling

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.

Accessibility

Progressive enhancement and no-JavaScript fallback

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.

Browser support

The component requires:

It 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.

Development

npm install
npm run test:run
npm run lint

License

MIT © Aaron Gustafson