1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
---
layout: default
title: Heading Permalink Extension
description: The HeadingPermalinkExtension makes all header elements linkable
redirect_from: /1.6/extensions/heading-permalinks/
---
# Heading Permalink Extension
This extension makes all of your heading elements (`<h1>`, `<h2>`, etc) linkable so that users can quickly grab a link to that specific part of the document - almost like the headings in this documentation!
**Tip:** You can combine this with the [Table of Contents extension](/1.x/extensions/table-of-contents/) to automatically generate a list of links to the headings in your documents.
## Installation
This extension is bundled with `league/commonmark`. This library can be installed via Composer:
```bash
composer require league/commonmark
```
See the [installation](/1.x/installation/) section for more details.
## Usage
This extension can be added to any new `Environment`:
```php
use League\CommonMark\Environment;
use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
use League\CommonMark\MarkdownConverter;
use League\CommonMark\Normalizer\SlugNormalizer;
// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
$environment = Environment::createCommonMarkEnvironment();
// Add this extension
$environment->addExtension(new HeadingPermalinkExtension());
// Set your configuration
$environment->mergeConfig([
// Extension defaults are shown below
// If you're happy with the defaults, feel free to remove them from this array
'heading_permalink' => [
'html_class' => 'heading-permalink',
'id_prefix' => 'user-content',
'insert' => 'before',
'title' => 'Permalink',
'symbol' => HeadingPermalinkRenderer::DEFAULT_SYMBOL,
'slug_normalizer' => new SlugNormalizer(),
],
]);
// Instantiate the converter engine and start converting some Markdown!
$converter = new MarkdownConverter($environment);
echo $converter->convertToHtml('# Hello World!');
```
## Configuration
This extension can be configured by providing a `heading_permalink` array with several nested configuration options. The defaults are shown in the code example above.
### `html_class`
The value of this nested configuration option should be a `string` that you want set as the `<a>` tag's `class` attribute. This defaults to `'heading-permalink'`.
### `id_prefix`
This should be a `string` you want prepended to HTML IDs. This prevents generating HTML ID attributes which might conflict with others in your stylesheet. A dash separator (`-`) will be added between the prefix and the ID. You can instead set this to an empty string (`''`) if you don't want a prefix.
### `inner_contents` _(deprecated since `1.5.0`)_
This controls the HTML you want to appear inside of the generated `<a>` tag. Usually this would be something you would
style as some kind of link icon, but you can replace this with any custom HTML you wish.
This option was deprecated in 1.5.0 and will be removed in 2.0.0. Use the `symbol` option instead.
This option has no default value and if one is provided, a deprecation warning will be triggered and the `symbol`
config option below will be ignored completely.
### `insert`
This controls whether the anchor is added to the beginning of the `<h1>`, `<h2>` etc. tag or to the end. Can be set to either `'before'` or `'after'`.
### `symbol`
This option sets the symbol used to display the permalink on the document. This defaults to `\League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_SYMBOL = '¶'`.
If you want to use a custom icon, then set this to an empty string `''` and check out the [Adding Icons](#adding-icons) sections below.
> Note: Special HTML characters (`" & < >`) provided here will be escaped for security reasons.
### `title`
This option sets the `title` attribute on the `<a>` tag. This defaults to `'Permalink'`.
### `slug_normalizer`
"Slugs" are the strings used within the `href`, `name`, and `id` attributes to identify a particular permalink.
By default, this extension will generate slugs based on the contents of the heading, just like GitHub-Flavored Markdown does.
You can change the string that is used as the "slug" by setting the `slug_normalizer` option to any class that implements `TextNormalizerInterface`.
For example, if you'd like each slug to be an MD5 hash, you could create a class like this:
```php
use League\CommonMark\Normalizer\TextNormalizerInterface;
final class MD5Normalizer implements TextNormalizerInterface
{
public function normalize(string $text, $context = null): string
{
return md5($text);
}
}
```
And then configure it like this:
```php
$config = [
'heading_permalink' => [
// ... other options here ...
'slug_normalizer' => new MD5Normalizer(),
],
];
```
Or you could use [PHP's anonymous class feature](https://www.php.net/manual/en/language.oop5.anonymous.php) to define the generator's behavior without creating a new class file:
```php
$config = [
'heading_permalink' => [
// ... other options here ...
'slug_normalizer' => new class implements TextNormalizerInterface {
public function normalize(string $text, $context = null): string
{
// TODO: Implement your code here
}
},
],
];
```
## Example
If you wanted to style your headings exactly like this documentation page does, try this configuration!
```php
$config = [
'heading_permalink' => [
'html_class' => 'heading-permalink',
'insert' => 'after',
'symbol' => '¶',
'title' => "Permalink",
],
];
```
Along with this CSS:
```css
.heading-permalink {
font-size: .8em;
vertical-align: super;
text-decoration: none;
color: transparent;
}
h1:hover .heading-permalink,
h2:hover .heading-permalink,
h3:hover .heading-permalink,
h4:hover .heading-permalink,
h5:hover .heading-permalink,
h6:hover .heading-permalink,
.heading-permalink:hover {
text-decoration: none;
color: #777;
}
```
## Styling Ideas
This library doesn't provide any CSS styling for the anchor element(s), but here are some ideas you could use in your own stylesheet.
You could hide the icon until the user hovers over the heading:
```css
.heading-permalink {
visibility: hidden;
}
h1:hover .heading-permalink,
h2:hover .heading-permalink,
h3:hover .heading-permalink,
h4:hover .heading-permalink,
h5:hover .heading-permalink,
h6:hover .heading-permalink
{
visibility: visible;
}
```
You could also float the symbol just a little bit left of the heading:
```css
.heading-permalink {
float: left;
padding-right: 4px;
margin-left: -20px;
line-height: 1;
}
```
These are only ideas - feel free to customize this however you'd like!
## Adding Icons
You can also use CSS to add a custom icon instead of providing a `symbol`:
```php
$config = [
'heading_permalink' => [
'html_class' => 'heading-permalink',
'symbol' => '',
],
];
```
Then targeting the `html_class` given in the configuration in your CSS:
```css
/**
* Custom SVG Icon.
*/
.heading-permalink::after {
display: inline-block;
content: "";
/**
* Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
* [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
*/
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-size: 1em;
}
```
|