KittyGiraudel/eleventy-plugin-footnotes

Feature request: allow users to specify class name on any element (without BEM)

AleksandrHovhannisyan opened this issue · 4 comments

Hi Kitty,

Thanks so much for this plugin!

I think it would be nice if the plugin exposed an API for adding a custom class name (or multiple class names) to any one of the individual elements that it renders, like the ol, li, or anchors. That way, it's more flexible and less opinionated out of the box.

For example, in my use case, I have a custom utility class that applies some standard styling to all lists. I want to be able to apply this class to the ol itself, but it's not currently possible to do this because the plugin strictly enforces BEM.

Here's how markdown-it-toc-done-right does things, just as an example:

.use(markdownItTocDoneRight, {
    listClass: 'list toc-list',
    itemClass: 'toc-item',
    linkClass: 'toc-link',
    listType: 'ol',
  })

The benefit of this is that you can still enforce BEM yourself while also including additional classes as needed.

Hey Aleksandr! 👋

That’s a fair suggestion! I think that would make sense to allow something like that. I’d accept an API proposal, followed by a PR if that’s something you want to give a shot at. :)

Sounds good!

I only have two ideas at the moment. Let me know which one you'd prefer and if you have any suggestions for tidying them up!

1. Individual class props

If baseClass is specified, the plugin enforces BEM for each element. But the plugin also exposes class props for each item, and these classes are chained along with the default BEM class. Maybe those props look like this:

  • refClass
  • titleClass
  • listClass
  • itemClass
  • backLinkClass

Alternatively, since this is a bit verbose for top-level options, maybe we could instead use a map:

{
  baseClass: 'footnotes',
  classes: {
    ref: 'ref',
    title: 'title',
    list: 'list',
    // etc.
  },
  // other options
}

2. Attribute map

This approach may be cleaner to implement since the plugin already has an attrs helper.

This is a generalization of the first approach, allowing users to pass in other attributes and not just a class name:

{
  baseClass: 'footnotes',
  attributes: {
    list: {
      class: 'list',
      another: 'attribute',
    },
    backLink: {
      class: 'styled-link',
      another: 'attribute',
    }
  }
}

The plugin would then key into the map and spread those attributes:

return `<a ${attrs({
      class: baseClass + '__ref',
      href: `#${id}-note`,
      id: `${id}-ref`,
      'aria-describedby': titleId,
      role: 'doc-noteref',
      ...attributes.footnoteRef,
    })}>${content}</a>`

This would cause problems for the class attribute since it would get overwritten if a user has specified a baseClass for BEM. Maybe we could use the clsx package to chain class names; not sure how you feel about adding a dependency, though.

Pros:

  • More flexible

Cons:

  • May allow for misuse of the plugin (e.g., overriding accessibility-related props)
  • May cause confusion regarding the class name prop (easily addressed w/ examples/docs)

Thank you for getting back to me with some suggestions! Given the plugin already gives baseClass and uses BEM, I would say the first option is the best right now. Shall we try that?

Sure! I'll put up a PR when I have some time. Thanks!