Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New IdAttributePlugin will add id attributes to your headings #3363

Closed
zachleat opened this issue Jul 12, 2024 · 6 comments
Closed

New IdAttributePlugin will add id attributes to your headings #3363

zachleat opened this issue Jul 12, 2024 · 6 comments

Comments

@zachleat
Copy link
Member

Rather than rely on template language specific plugins for id attributes, a la this one https://www.npmjs.com/package/markdown-it-anchor we can instead make use of the existing posthtml infrastructure used by the HTML base plugin and the input path to URL plugins to add an id attributes to content.

This then pairs nicely with a web component to add anchors to headings for the UX piece, a la @daviddarneshttps://github.com/daviddarnes/heading-anchors

@zachleat zachleat added this to the Eleventy 3.0.0 milestone Jul 12, 2024
@zachleat zachleat self-assigned this Jul 12, 2024
@zachleat
Copy link
Member Author

zachleat commented Jul 12, 2024

<h1>Hello</h1>
<h2 id="already-has-an-id">Subheading</h1>

becomes

<h1 id="hello">Hello</h1>
<h2 id="already-has-an-id">Subheading</h1>

Simple usage

import { IdAttributePlugin } from "@11ty/eleventy";

export default function (eleventyConfig) {
	eleventyConfig.addPlugin(IdAttributePlugin);
};

Full options:

import { IdAttributePlugin } from "@11ty/eleventy";

export default function (eleventyConfig) {
	eleventyConfig.addPlugin(IdAttributePlugin, {
		// custom slugify function, otherwise we use Eleventy’s built-in `slugify` filter.
		slugify: function(textContent) {
			// …
		},
		selector: "h1,h2,h3,h4,h5,h6", // default
	});
};

Duplicate headings are de-duped using -1, -2, -3 suffixes (etc) on a per-page level. Use the eleventy:id-ignore attribute to ignore a node’s content for the purposes of id generation.

@zachleat zachleat changed the title New id Attribute plugin will add id attributes to your headings (multi-template-language support) New IdAttributePlugin will add id attributes to your headings Jul 12, 2024
zachleat added a commit that referenced this issue Jul 12, 2024
@zachleat
Copy link
Member Author

(Has the added benefit of removing the unnecessary link markup from your RSS feeds too!)

rdela added a commit to rdela/eleventeen that referenced this issue Jul 21, 2024
- use new IdAttributePlugin, makes “use of the existing posthtml
  infrastructure used by the HTML base plugin and the input path to URL
  plugins to add” slugified `id` attrs.
  Has the added benefit of removing the unnecessary link markup from your
  RSS feeds too!
  11ty/eleventy#3363
- rm markdownItAnchor and comment out header-anchor css
- eleventeen.png instead of eight-million.jpg in thirdpost.md
- upd eleventy + eleventy-plugin-rss

9.2.20-alpha.17
rdela added a commit to rdela/eleventeen that referenced this issue Jul 21, 2024
- use new IdAttributePlugin, makes “use of the existing posthtml
  infrastructure used by the HTML base plugin and the input path to URL
  plugins to add” slugified `id` attrs.
  Has the added benefit of removing the unnecessary link markup from your
  RSS feeds too!
  11ty/eleventy#3363
- rm markdownItAnchor and comment out header-anchor css
- eleventeen.png instead of eight-million.jpg in thirdpost.md
- upd eleventy + eleventy-plugin-rss

9.2.20-alpha.17
rdela added a commit to rdela/eleventeen that referenced this issue Jul 21, 2024
- use new IdAttributePlugin, makes “use of the existing posthtml
  infrastructure used by the HTML base plugin and the input path to URL
  plugins to add” slugified `id` attrs.
  Has the added benefit of removing the unnecessary link markup from your
  RSS feeds too!
  11ty/eleventy#3363
- rm markdownItAnchor and comment out header-anchor css
- eleventeen.png instead of eight-million.jpg in thirdpost.md
- upd eleventy + eleventy-plugin-rss

9.2.20-alpha.17
* trunk:
  eleventy 3.0.0-alpha.17, IdAttributePlugin, eleventeen.png (#39)
rdela added a commit to rdela/eleventeen that referenced this issue Jul 25, 2024
At least until [#40](#40) finds
resolution, building on the work in
[#39](#39), adding
[daviddarnes/heading-anchors](https://github.com/daviddarnes/heading-anchors)
per rec in [11ty/eleventy #3363](11ty/eleventy#3363)

Used `position="beforeend"` and styled with a slight adjustment to
[demo-styling], adding `vertical-align: bottom;` to `a[href^="#"]` and
constraining styles to `heading-anchors` element.

demo-styling: https://github.com/daviddarnes/heading-anchors/blob/main/demo-styling.html#L11-L25
rdela added a commit to rdela/eleventeen that referenced this issue Jul 25, 2024
* add @daviddarnes/heading-anchors

At least until [#40](#40) finds
resolution, building on the work in
[#39](#39), adding
[daviddarnes/heading-anchors](https://github.com/daviddarnes/heading-anchors)
per rec in [11ty/eleventy #3363](11ty/eleventy#3363)

Used `position="beforeend"` and styled with a slight adjustment to
[demo-styling], adding `vertical-align: bottom;` to `a[href^="#"]` and
constraining styles to `heading-anchors` element.

[demo-styling]: https://github.com/daviddarnes/heading-anchors/blob/main/demo-styling.html#L11-L25

* move heading-anchors code to base.njk instead of post.njk

  - add hover + focus styles for anchor links
  - delete deprecated css
  - 9.2.21-alpha.17
rdela added a commit to rdela/eleventeen that referenced this issue Jul 25, 2024
* add @daviddarnes/heading-anchors

At least until #40 finds
resolution, building on the work in #39
adding https://github.com/daviddarnes/heading-anchors per rec in
11ty/eleventy#3363

Used `position="beforeend"` and styled with a slight adjustment to
https://github.com/daviddarnes/heading-anchors/blob/main/demo-styling.html#L11-L25

adding `vertical-align: bottom;` to `a[href^="#"]` and constraining styles to
`heading-anchors` element.

* move heading-anchors code to base.njk instead of post.njk

  - add hover + focus styles for anchor links
  - delete deprecated css
@zachleat zachleat added the needs-documentation Documentation for this issue/feature is pending! label Jul 30, 2024
zachleat added a commit to 11ty/11ty-website that referenced this issue Sep 30, 2024
@zachleat
Copy link
Member Author

Temporary docs preview url deploying: https://11ty-website-git-v3-11ty.vercel.app/docs/plugins/id-attribute/

@zachleat zachleat removed the needs-documentation Documentation for this issue/feature is pending! label Sep 30, 2024
zachleat added a commit to 11ty/11ty-website that referenced this issue Sep 30, 2024
@SQLkiwi
Copy link

SQLkiwi commented Oct 15, 2024

Just to note this enhancement seems to add id attributes too late for table of contents generation in a layout.
Why it wasn't working puzzled me for a while, so perhaps the documentation could be clearer on timing?
I ended up reverting to markdown-it-anchor for my particular usage.

@kleinfreund
Copy link
Contributor

kleinfreund commented Oct 20, 2024

Mainly leaving something here in case others expand on the use of this plugin for generating headings with self-linking anchors.


Is there a way to use this plugin (which I'd like as it can add IDs to all HTML not just Markdown) and have some manner of injected HTML in a heading? I currently use markdown-it-anchor not only to add the IDs but also to add some custom markup inside anchors, most notably an anchor link pointing to the heading's ID.

I can see using a custom element for this but I don't want to add any JavaScript to my site as this can be done at build time.


My own experiment so far:

In the following Eleventy config, I stripped out every one of my other settings and left only what I added now to add anchors to existing headings combining the IdAttributePlugin with a cheerio-based Eleventy transform.

In my setup, this allows me to throw out markdown-it-anchor so technically, I don't need to customize the selector option to ignore headings that already have anchors.

Note that I only tried replicating my existing setup for anchors here. It's likely that adding the anchor markup outside of the actual heading is better for overall accessibility.

eleventy.config.js:

import { IdAttributePlugin } from '@11ty/eleventy'
import * as cheerio from 'cheerio'

export default function (eleventyConfig) {
  eleventyConfig.addTransform('inject_heading_anchors', createInjectHeadingAnchors({
    selector: '[id]:is(h2,h3,h4,h5,h6):not(:has(> .header-anchor))',
  }))
}

/**
 * @typedef {object} InjectHeadingAnchorsOptions
 * @property {string} [selector]
 */

/** @type {Required<InjectHeadingAnchorsOptions>} */
const injectHeadingAnchorsDefaultOptions = {
  selector: '[id]:is(h2,h3,h4,h5,h6)',
}

/**
 * @param {InjectHeadingAnchorsOptions} [options]
 * @returns {(content: string) => string}
 */
function createInjectHeadingAnchors(options) {
  return function (content) {
    return injectHeadingAnchors(content, options)
  }
}

/**
 * @param {string} content
 * @param {InjectHeadingAnchorsOptions} [options]
 * @returns {string}
 */
function injectHeadingAnchors(content, options) {
  /** @type {Required<InjectHeadingAnchorsOptions>} */
  const optionsWithDefaults = {
    ...injectHeadingAnchorsDefaultOptions,
    ...options,
  }

  const $ = cheerio.load(content)
  $(optionsWithDefaults.selector).map((_i, el) => {
    const $heading = $(el)
    $heading.attr('tabindex', '-1')

    $heading.prepend(`<a class="header-anchor" href="#${$heading.attr('id')}">
      <span class="header-anchor__icon">
        <b>#</b>
        <span class="visually-hidden">Jump to heading</span>
      </span>
    </a>`)

    return $heading
  })

  return $.html()
}

@rolandsaven
Copy link

Unfortunately, it does not work with eleventy-plugin-toc plugin, and the others out there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants