Skip to content

Conversation

CollierCZ
Copy link
Owner

@CollierCZ CollierCZ commented Aug 20, 2025

Closes #20

To do:

  • Make it opt-in, instead of opt-out
  • Export heading node for use in customization
  • Add tests for custom components with the IDs
  • Add tests for opting in
  • Update docs with example

Copy link
Contributor

@Greenheart Greenheart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really promising! Great work so far :)

Comment on lines 31 to 42
const getSlug = (
attributes: Record<string, any>, // eslint-disable-line @typescript-eslint/no-explicit-any
children: RenderableTreeNode[],
): string => {
if (attributes.id && typeof attributes.id === "string") {
return attributes.id;
}
return slugify(getTextContent(children), {
lower: true,
strict: true,
}) as string;
};
Copy link
Contributor

@Greenheart Greenheart Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my use case (and it's likely similar for others), it's important to control the slugification to get the desired output for URLs.

Looking at the source code for slugify, the default locale replacements for the sv locale would replace for example å with aa. However, that won't work with my requirements.

var locales = {
  "sv":{"&":"och","Å":"AA","Ä":"AE","Ö":"OE","å":"aa","ä":"ae","ö":"oe"}
}

Proposed solutions

  1. Allow users of the library to pass in the Options and/or call slugify.extend(). However this adds the risk of breaking changes in markdoc-svelte whenever the slugify library is updated. Not very likely, but one should always be careful when exposing external types from third-party code.

  2. The other, and in my opinion much better option is to change the new option headingIds to have the type boolean | (value: string) => string, which allows passing in a custom slugger function. If the function is provided, we have a truthy value and thus know when to enable the headingIds slugger.

Option 2 allows us to:

  1. Enable and disable slugging by passing headingIds: true | false
  2. markdoc-svelte could use the default slugger if the option is set to true.
  3. And finally, we could use the custom slugger implemented by the user or markdoc-svelte

I prefer the final option since that gives much more flexibility.

Curious to hear your thoughts about this! :)

NOTE: If we were to change the above, it might be suitable to implement as part of a follow-up branch, just to keep this one as clean as possible.

NOTE 2: If we go for option 2, and we have no other use for the slugger in markdoc-svelte, then we might remove that dependency and let users provide a slugger function if they want slugged ids for headings. This simplified markdoc-svelte.

There is also a third option - to use @sindresorhus/slugify which exports an Option type and has a good, flexible API. It has also been stable for the past years. If we were to use that library instead, I'd be happy to just pass in headingIds?: SlugifyOptions and if the options are empty or non-existant, slugification is disabled. Otherwise enable it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea, and agree that option 2 is nice.
Originally added slugify only because it was quick and got the job done - did not think at all about the desired format of the slugs.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See if it works better for you now. I switched to slug over slugify as it seemed like the default was better (defaults to lowercase), which seemed to make it easier to set up if there aren't any requirements.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow the generated id attributes to be rendered by custom heading nodes

3 participants