Content: [Markdown] Decide what to do about <dl>

Created on 22 Apr 2021  ·  28Comments  ·  Source: mdn/content

In MDN we use <dl> (description lists aka definition lists) quite extensively, and they're not natively supported in GFM.

A quick look at the JS docs tells us what we already know: in 922 pages:

  • 518 of them use a description list at least once
  • 800 description lists are used in total

They're most commonly used for:

  • listing parameters of functions
  • listing exceptions thrown by functions
  • listing properties and methods of objects

Some options:

Generate them

If we could generate these lists (in a macro, or directly in Yari) we could of course emit HTML, and could then use <dl>.

We could possibly generate the lists of properties and methods in the future, because they are lists of links to separate pages. But it's difficult to see how we'd do the same for lists of parameters or exceptions. So this definitely isn't a solution now and probably isn't a complete solution ever.

Stop using them

There are so many of these that converting them would be hard, and it's hard to argue that they are not an appropriate choice for things like lists of parameters.

Use raw HTML

Unlike something like a note, where you just need opening and closing HTML tags and can have Markdown inside, using raw HTML for <dl> commits you of course to raw HTML for <dt> and <dd> as well. So you will end up with a lot of raw HTML here. It's not an attractive option.

Extend GFM

This leads us to the extend-GFM option. The most popular choice here is the one used in Kramdown:

First Term
: This is the definition of the first term.
: This is a second definition of the first term.

Second Term
: This is the definition of the second term.
<dl>
  <dt>First Term</dt>
  <dd>This is the definition of the first term.</dd>
  <dd>This a second definition of the first term.</dd>
  <dt>Second Term</dt>
  <dd>This is the definition of the second term. </dd>
</dl>

Kramdown describes this syntax in some detail: https://kramdown.gettalong.org/syntax.html#definition-lists and it's not very clear to me how much we would want to adopt this definition wholesale or how much we would want or need to constrain it. Not to mention what it would be like to implement: it would be really interesting to hear what @Gregoor thinks about that. I don't know if there is already a Unified handler to support this syntax.

(One obvious point is that we wouldn't support inline attribute lists (IALs, https://kramdown.gettalong.org/syntax.html#inline-attribute-lists.)

needs-triage

Most helpful comment

I have had a go at writing this up -> https://github.com/mdn/content/pull/4987.

All 28 comments

My vote is for the "Extend GFM" option. My main concerns with this are:

  1. How well it displays on GitHub. I'm expecting it to be OK; the colon at start of sentence is quite distinctive.
  2. How well it works when nesting other content inside of dd/dt. If this is an issue, would it be an option to see how many complex dls we have, and look to convert them to something else, or just constain usage of this syntax to simple dls and do something else for complex exceptions.

Here is another idea, how about we re-use markdown tables for definition lists? We could turn 2-columned tables with headers like in the example into definition lists.

Example:

$dt | $dd
-- | --
variable | On each iteration a value of a different property is assigned to variable. variable may be declared with const, let, or var.
iterable | Object whose iterable properties are iterated.

Upside:

  • no new syntax
  • renders nicely on GitHub

Downside:

  • overloads table syntax

Extending GFM feels a bit like going towards a MediaWiki-esque syntax in my opinion.

Nesting is an interesting point. Even if we went into the table variant @Gregoor described, that wouldn't save us completely (think of nested tables).

Ideally, I'd like to see some generated.
But that requires either a macro (we want to get away from them) to demark the position where the <dl> shall be injected - or a well-defined position within the page. How would you define that? I could imagine a HTML comment here …

I'm with extending GFM. For your edification, below is HTML, Kramdown and table version taken from a page in the docs.

  • The Kramdown syntax is pretty well understood and works OK in github. It also can support nested markdown so you can convert everything.
  • I really like Gregoor's suggestion too. It would work for almost every table. However it is not quite as flexible because:

    • you can't easily nest things like bulleted lists inside a markdown table. Below I just removed the list.

    • Having a second definition for a term doesn't look great (I added a case below to demo). You could render this in other ways of course, but hard to automate the conversion.


Raw HTML version

Cascade and inheritance
The aim of this lesson is to develop your understanding of some of the most fundamental concepts of CSS — the cascade, specificity, and inheritance — which control how CSS is applied to HTML and how conflicts are resolved.
CSS selectors
There are a wide variety of CSS selectors available, allowing for fine-grained precision when selecting elements to style. In this article and its sub-articles, we'll run through the different types in great detail, seeing how they work. The sub-articles are as follows:
The box model
Everything in CSS has a box around it, and understanding these boxes is key to being able to create layouts with CSS, or to align items with other items. In this lesson, we will take a proper look at the CSS Box Model, in order that you can move onto more complex layout tasks with an understanding of how it works and the terminology that relates to it.
Backgrounds and borders
In this lesson we will take a look at some of the creative things you can do with CSS backgrounds and borders. From adding gradients, background images, and rounded corners, backgrounds and borders are the answer to a lot of styling questions in CSS.
Handling different text directions
In recent years, CSS has evolved in order to better support different directionality of content, including right-to-left but also top-to-bottom content (such as Japanese) — these different directionalities are called writing modes. As you progress in your study and begin to work with layout, an understanding of writing modes will be very helpful to you, therefore we will introduce them in this article.
Overflowing content
In this lesson we will look at another important concept in CSS — overflow. Overflow is what happens when there is too much content to be contained comfortably inside a box. In this guide, you will learn what it is and how to manage it.
CSS values and units
Every property used in CSS has a value or set of values that are allowed for that property. In this lesson, we will take a look at some of the most common values and units in use.
Sizing items in CSS
In the various lessons so far you have come across a number of ways to size items on a web page using CSS. Understanding how big the different features in your design will be is important, and in this lesson, we will summarize the various ways elements get a size via CSS and define a few terms around sizing that will help you in the future.
Images, media, and form elements
In this lesson we will take a look at how certain special elements are treated in CSS. Images, other media, and form elements behave a little differently in terms of your ability to style them with CSS than regular boxes. Understanding what is and isn't possible can save some frustration, and this lesson will highlight some of the main things that you need to know.
Styling tables
Styling an HTML table isn't the most glamorous job in the world, but sometimes we all have to do it. This article provides a guide to making HTML tables look good, with some specific table styling techniques highlighted.
Debugging CSS
Sometimes when writing CSS you will encounter an issue where your CSS doesn't seem to be doing what you expect. This article will give you guidance on how to go about debugging a CSS problem, and show you how the DevTools included in all modern browsers can help you find out what is going on.
Organizing your CSS
As you start to work on larger stylesheets and big projects you will discover that maintaining a huge CSS file can be challenging. In this article, we will take a brief look at some best practices for writing your CSS to make it easily maintainable, and some of the solutions you will find in use by others to help improve maintainability.


Kramdown version

Cascade and inheritance
:The aim of this lesson is to develop your understanding of some of the most fundamental concepts of CSS — the cascade, specificity, and inheritance — which control how CSS is applied to HTML and how conflicts are resolved.

CSS selectors
:There are a wide variety of CSS selectors available, allowing for fine-grained precision when selecting elements to style. In this article and its sub-articles, we'll run through the different types in great detail, seeing how they work. The sub-articles are as follows:

The box model
:Everything in CSS has a box around it, and understanding these boxes is key to being able to create layouts with CSS, or to align items with other items. In this lesson, we will take a proper look at the CSS _Box Model_, in order that you can move onto more complex layout tasks with an understanding of how it works and the terminology that relates to it.

Backgrounds and borders
:In this lesson we will take a look at some of the creative things you can do with CSS backgrounds and borders. From adding gradients, background images, and rounded corners, backgrounds and borders are the answer to a lot of styling questions in CSS.

Handling different text directions
:In recent years, CSS has evolved in order to better support different directionality of content, including right-to-left but also top-to-bottom content (such as Japanese) — these different directionalities are called writing modes. As you progress in your study and begin to work with layout, an understanding of writing modes will be very helpful to you, therefore we will introduce them in this article.

Overflowing content
:In this lesson we will look at another important concept in CSS — overflow. Overflow is what happens when there is too much content to be contained comfortably inside a box. In this guide, you will learn what it is and how to manage it.

CSS values and units
:Every property used in CSS has a value or set of values that are allowed for that property. In this lesson, we will take a look at some of the most common values and units in use.

Sizing items in CSS
:In the various lessons so far you have come across a number of ways to size items on a web page using CSS. Understanding how big the different features in your design will be is important, and in this lesson, we will summarize the various ways elements get a size via CSS and define a few terms around sizing that will help you in the future.

Images, media, and form elements
:In this lesson we will take a look at how certain special elements are treated in CSS. Images, other media, and form elements behave a little differently in terms of your ability to style them with CSS than regular boxes. Understanding what is and isn't possible can save some frustration, and this lesson will highlight some of the main things that you need to know.

Styling tables
:Styling an HTML table isn't the most glamorous job in the world, but sometimes we all have to do it. This article provides a guide to making HTML tables look good, with some specific table styling techniques highlighted.

Debugging CSS
:Sometimes when writing CSS you will encounter an issue where your CSS doesn't seem to be doing what you expect. This article will give you guidance on how to go about debugging a CSS problem, and show you how the DevTools included in all modern browsers can help you find out what is going on.

Organizing your CSS
:As you start to work on larger stylesheets and big projects you will discover that maintaining a huge CSS file can be challenging. In this article, we will take a brief look at some best practices for writing your CSS to make it easily maintainable, and some of the solutions you will find in use by others to help improve maintainability.


Table version

dt | dl
--- | ---
Cascade and inheritance | The aim of this lesson is to develop your understanding of some of the most fundamental concepts of CSS — the cascade, specificity, and inheritance — which control how CSS is applied to HTML and how conflicts are resolved.
CSS selectors|There are a wide variety of CSS selectors available, allowing for fine-grained precision when selecting elements to style. In this article and its sub-articles, we'll run through the different types in great detail, seeing how they work. The sub-articles are as follows: Type, class, and ID selectors, Attribute selectors, Pseudo-classes and pseudo-elements, Combinators
The box model | Everything in CSS has a box around it, and understanding these boxes is key to being able to create layouts with CSS, or to align items with other items. In this lesson, we will take a proper look at the CSS _Box Model_, in order that you can move onto more complex layout tasks with an understanding of how it works and the terminology that relates to it.
  | A second term, just to show a demo.
Backgrounds and borders | In this lesson we will take a look at some of the creative things you can do with CSS backgrounds and borders. From adding gradients, background images, and rounded corners, backgrounds and borders are the answer to a lot of styling questions in CSS.
Handling different text directions|In recent years, CSS has evolved in order to better support different directionality of content, including right-to-left but also top-to-bottom content (such as Japanese) — these different directionalities are called writing modes. As you progress in your study and begin to work with layout, an understanding of writing modes will be very helpful to you, therefore we will introduce them in this article.
Overflowing content | In this lesson we will look at another important concept in CSS — overflow. Overflow is what happens when there is too much content to be contained comfortably inside a box. In this guide, you will learn what it is and how to manage it.
CSS values and units | Every property used in CSS has a value or set of values that are allowed for that property. In this lesson, we will take a look at some of the most common values and units in use.
Sizing items in CSS | In the various lessons so far you have come across a number of ways to size items on a web page using CSS. Understanding how big the different features in your design will be is important, and in this lesson, we will summarize the various ways elements get a size via CSS and define a few terms around sizing that will help you in the future.
Images, media, and form elements | In this lesson we will take a look at how certain special elements are treated in CSS. Images, other media, and form elements behave a little differently in terms of your ability to style them with CSS than regular boxes. Understanding what is and isn't possible can save some frustration, and this lesson will highlight some of the main things that you need to know.
Styling tables | Styling an HTML table isn't the most glamorous job in the world, but sometimes we all have to do it. This article provides a guide to making HTML tables look good, with some specific table styling techniques highlighted.
Debugging CSS | Sometimes when writing CSS you will encounter an issue where your CSS doesn't seem to be doing what you expect. This article will give you guidance on how to go about debugging a CSS problem, and show you how the DevTools included in all modern browsers can help you find out what is going on.
Organizing your CSS | As you start to work on larger stylesheets and big projects you will discover that maintaining a huge CSS file can be challenging. In this article, we will take a brief look at some best practices for writing your CSS to make it easily maintainable, and some of the solutions you will find in use by others to help improve maintainability.

  • Will, FYI I updated the description above to include possible second definition for a term

Thanks for all the thoughts, and thanks Hamish for showing the different syntaxes!

Here is another idea, how about we re-use markdown tables for definition lists? We could turn 2-columned tables with headers like in the example into definition lists.

I think this would be OK too. I think it's not strictly true to say "no new syntax" though, there is a new syntax, just one based on tables. I think as Hamish says, the Kramdown option seems quite commonly understood, and yes, it looks all right in the source.

About nesting: it is a thing. I count 57 pages in the JS docs where <dl> or <ul> is nested under a <dl>. Usually this is for things like callback arguments that take parameters, or listing the possible values that a parameter can have.

https://developer.mozilla.org/en-us/web/javascript/guide/regular_expressions/cheatsheet
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/every
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/filter
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/find
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/findindex
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/flatmap
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/foreach
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/map
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/reduce
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/reduceright
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/some
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/array/sort
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/date/date
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/generator/throw
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/collator/collator
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/collator/collator
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/collator/supportedlocalesof
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/datetimeformat/datetimeformat
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/datetimeformat/datetimeformat
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/datetimeformat/datetimeformat
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/datetimeformat/supportedlocalesof
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/displaynames/displaynames
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/displaynames/displaynames
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/displaynames/of
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/displaynames/supportedlocalesof
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/listformat/listformat
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/listformat/supportedlocalesof
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/numberformat/numberformat
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/numberformat/numberformat
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/numberformat/supportedlocalesof
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/pluralrules/pluralrules
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/pluralrules/pluralrules
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/pluralrules/supportedlocalesof
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/relativetimeformat/relativetimeformat
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/relativetimeformat/relativetimeformat
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/relativetimeformat/resolvedoptions
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/intl/relativetimeformat/supportedlocalesof
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/map/foreach
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/object/__definesetter__
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/object/defineproperties
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/promise/catch
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/regexp/compile
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/regexp/regexp
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/set/foreach
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/string/normalize
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/string/split
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/typedarray/every
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/typedarray/find
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/typedarray/findindex
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/typedarray/foreach
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/typedarray/map
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/typedarray/reduce
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/typedarray/reduceright
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/typedarray/some
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/webassembly/global/global
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/webassembly/memory/memory
https://developer.mozilla.org/en-us/web/javascript/reference/global_objects/webassembly/table/table

Ideally, I'd like to see some generated.
But that requires either a macro (we want to get away from them) to demark the position where the \

shall be injected - or a well-defined position within the page. How would you define that? I could imagine a HTML comment here …

Well... we could generate _some_ of them, with a bit of work. And yes, we kinda want to get away from macros, eventually, but you need some code to generate things, and it has to live somewhere, and KS macros are the current somewhere.

For lists of pages, like, say, the static methods of Array, you could have (let's call it) a "thing" embedded in the page, that says "insert a list of the static methods right here", and when Yari builds the page it resolves that by finding the list of static methods (perhaps by convention, by finding the subpages with a "js-static-method" page type). Whether this work is done in a KS macro or in Yari platform code, that general solution is the same.

(Or, you could have something more structured, where a JS class page always gets a front matter item pointing at the pages describing its static methods, and Yari just knows that when it sees this it has to insert the list of pages at the defined location for that piece of content.)

But how would you do either of those things for, say, lists of parameters? You'd have to make authors semantically mark up that content somehow, so your builder can recognise it, and this makes writing an exercise in form-filling, which really goes against the idea of Markdown as a way of making authoring easier. So I think although we could (and eventually should) generate lots of <dl> elements, (1) that's in a further future and (2) we will probably still even then have a need for hand-written <dl> elements.

About nesting: it is a thing. I count 57 pages in the JS docs where <dl> or <ul> is nested under a <dl>. Usually this is for things like callback arguments that take parameters, or listing the possible values that a parameter can have.

I was careless when I said this would all just work - needs a bit more thought for this case. While you can express a nested list kind of unambiguously you can't do so with this definition list syntax. That's because the first line has no marker. To markdown "ordinary rules" the new definition list looks like line continuations. Here is an example showing it failing:

locales
:A string with a BCP 47 language tag, or an array of such strings. For the general form of the locales ...
options {{optional_inline}}
:An object that may have the following property:
localeMatcher
:The locale matching algorithm to use. Possible values are "lookup" and "best fit"; the default is "best fit". For information about this option, see the...

I'm not sure how you would resolve this case in a way that works with github :-(

I don't know if there is already a Unified handler to support this syntax.

I know there's at least one partial implementation of the definition list: https://github.com/Symbitic/remark-plugins/tree/master/packages/remark-deflist. It has a limitation of only supporting single-paragraph definitions. Looking at the implementation, I'd guess that generalizing it to any sort of block is rather more complex. I'm not quite sure if _can_ be done without actually implementing a new syntax at the micromark level.

Overloading lists

I have another proposal, inspired by the table suggestion and reStructuredText's list tables: how about using a magic unordered list?

We could have something like this:

source

* deflist
* term 1
  * definition 1
  * definition 2
* term 2
  * etc.

rendered (GFM)

  • deflist
  • term 1

    • definition 1

    • definition 2

  • term 2

    • etc.

rendered (Yari)

<dl>
  <dt>term 1</dt>
  <dd>definition 1</dd>
  <dd>definition 2</dd>
  <dt>term 2</dt>
  <dd>etc.</dd>
</dl>
term 1
definition 1
definition 2
term 2
etc.

There's other variations you could do (e.g., using a magic word at the start of each <li>, put deflist outside the list, use an ordered list, etc.), but this is the overall idea.

It has the same upsides as the table: no new syntax and renders nicely in GitHub. It also adds a couple of benefits on top: it doesn't use the unpleasant table syntax and accommodates block-level content inside definitions (raised by @wbamberg). It has a new downside of relying on a magic word, but we have already done that for notes and warnings.

As an implementation, transforming the underlying <ul> tree wouldn't be terribly complex, so you could implement it without directly parsing the source. (Some of the variations aren't so easy to implement, but most are.)

What I like about @ddbeck suggestion of overloading lists https://github.com/mdn/content/issues/4367#issuecomment-827553513 is that it allows nested deflists, which is something that we do have in our sources. If we went this approach would be good to have a more visible keyword/list marker.

What I like about using the extended GFM is that it is clearly NOT an ordinary list. But that only supports single level. Can we live with that? Well, we can if we explicitly state that for the small number of nested definition list cases you can use HTML.

Upshot, IMO the overloaded lists is the best option I've seen so far.

What I like about using the extended GFM is that it is clearly NOT an ordinary list. But that only supports single level. Can we live with that? Well, we can if we explicitly state that for the small number of nested definition list cases you can use HTML.

By "extended GFM" do you mean what Kramdown does or something else? Because Kramdown does allow nesting (although the Unified implementation Daniel linked to above does not).

I'm not happy about it but I do think it will be difficult to live without nesting in our current docs.

I meant Kramdown. How does that do nesting?

According to https://kramdown-sandbox.herokuapp.com/ , this markup:

: a thing

    A
    : another thing

    B
    : a different thing

Two
: back to the outer list

...gives us this HTML:

<dl>
  <dt>One</dt>
  <dd>a thing
    <dl>
      <dt>A</dt>
      <dd>another thing</dd>
      <dt>B</dt>
      <dd>a different thing</dd>
    </dl>
  </dd>
  <dt>Two</dt>
  <dd>back to the outer list</dd>
</dl>

For authoring, I think I like the Kramdown syntax better, but @ddbeck 's would be OK too. And I agree that we should consider how hard it is to implement extensions.

I was going to say that as far as I know we almost never use multiple definitions for a single term, so it would probably be fine not to support this. But then I looked.... and we do things like this:

https://github.com/mdn/content/blob/d9638211374d788be1eb8c6ca21af5d8229e27b9/files/en-us/web/javascript/reference/global_objects/array/slice/index.html#L31-L53

...which is obviously broken. There aren't too many of these (in JS at least), and I'd be open to trying to fix this markup. Unfortunately it's hard to automate since sometimes there might be actual real multiple definitions. I think hardly ever though.

Thanks @wbamberg

Yes, we use nested lists a bit, mainly for options of arguments. I have a slight leaning towards Kramdown syntax too (for the same reason). As shown below, neither is awesome in github.


One
: a thing

A
: another thing

B
: a different thing

Two
: back to the outer list


  • deflist
  • One

    • deflist

    • A

    • another thing

    • B

    • a differentthing

  • Two

    • back to the outer list

I really like @ddbeck’s suggestion in https://github.com/mdn/content/issues/4367#issuecomment-827553513 best. I think that’s the easiest thing for authors/contributors — it doesn’t require them to learn a new syntax. That along with the other advantages it has (ability to nest, ability to contain block content) seems to make it a pretty neat solution.

Also, I have a lot of experience creating and wrestling with normal lists in markdown — and I imagine we all do, and most contributors probably would as well. And that experience includes knowing already about some of the quirks it has — e.g., how to do nesting correctly, and how to include block content.

I think the "Extend GFM" option could possibly also be a viable solution, but I can’t speak from experience, because I’ve never used it anywhere yet — in contrast to having a lot of experience with using the normal list syntax in @ddbeck’s suggestion.

So it seems like the "Extend GFM" option is more of an unknown than the just-use-normal-lists-with-magic-keyword solution that @ddbeck proposed — that is, the "Extend GFM" option is more of risk to buy into than solution @ddbeck proposes.

I’d also be happy with the table-based way that @Gregoor suggested in https://github.com/mdn/content/issues/4367#issuecomment-825153476 — if it handled block content. But from what others have said in this issue and elsewhere, it sounds like it doesn’t handle block content. If so, that’d kinda make it seem to be a non-starter.

I most dislike the "Use raw HTML" option, by a wide margin. Adopting that and telling authors/contributors they need to use it would seem to me to sort of being giving up on the fundamentals of why we’re making this move to begin with. If we’re going to help authors move away from being required to author in HTML to contribute to MDN, let’s really move away — all the way.

I can live with either, and I keep changing my mind about which I prefer - right now it's the @ddbeck solution because I value github rendering. But if we did that I would prefer a much more obvious deflist identifier string.

I think there is clear leaning towards the two discussed above ^^^. Are we at the point of a vote?

Something to think about for any choice here: I suspect that, longer-term, there will be a lot of interest in giving structure to the things that we typically use definition lists for. For instance, it might be really nice to have separate files for object properties, with a more structured format (that we can check against IDL and the like), that can be used as source data for generating definition lists. It's likely that whatever we choose here is going to end up transitional (or niche use).

it might be really nice to have separate files for object properties, with a more structured format (that we can check against IDL and the like), that can be used as source data for generating definition lists

So that would be something like what we do with https://github.com/mdn/data for CSS syntax now, right?

I can imagine that as the basis for object properties, we could maintain copies of the IDL blocks, and use an IDL parser and some code to generate the documentation stubs that we then populate.

I think that unlike the CSS syntax case, we would need something more complicated like that in this case, because for object properties, we also have a lot of unstructured free-form prose that accompanies the structured (from IDL) information.

But all that said, once we get to that point, it seems like we’d still have the same problem as we do now, as far as needing to decide on some list syntax for authors to use. I mean, the authors wouldn’t need to touch the structured (IDL) source — but they’d still need to author the part that provides the free-form prose descriptions, associated with (mapped to) each IDL member.

The only alternatives I could imagine for managing the free-form prose in a way that associated it with the structured parts would be to add comments to the IDL, and extract those comments in the build — or else to manage the whole thing as JSON instead. But those clearly have pretty big disadvantages over having the source for the prose parts be in markdown.

So that would be something like what we do with https://github.com/mdn/data for CSS syntax now, right?

@sideshowbarker I don't want to get too far off-topic here, but in this case, I'm talking about revisiting some of the ideas that came out of Stumptown. For content about things which are themselves highly structured, I think there's the possibility of doing stuff like tightly controlling the form and sequence of Markdown headings to describe named parts of interfaces. It decouples authorship a bit (i.e., you're writing sections that become entries in a definition list), but that might be desirable, because you can use that structure produce other content (e.g., reuse across pages or editor tooltips) from the same source.

I think this is the same thing I talked about upthread: https://github.com/mdn/content/issues/4367#issuecomment-825364512.

But two things, as noted in https://github.com/mdn/content/issues/4367#issuecomment-825364512:

  • that is some way off still
  • although that will reduce the number of <dl> elements we need, many such lists will be difficult to structure ever.

So we still need a way to represent <dl> in Markdown, now and probably quite far into the future as well.

I'd like to try to resolve this, and unless more facts come to light, or unless @Gregoor thinks it's not practical to implement it, I'm in favour of the Kramdown syntax.

The main reason for this is that it's by a long way the most common Markdown syntax for <dl>, and the nearest thing to a standard. This has a few benefits:

  • people have put in the work to specify and implement it, and we can take advantage of that work
  • authors with Markdown experience are more likely to be familiar with it
  • if CommonMark does end up supporting <dl>, there's a reasonable chance that it will look like the Kramdown syntax, and there's virtually no chance it will look like any syntax we invent in this thread.

Please see also this thread about the possibility of adding <dl> support into CommonMark, which has lots of background about the Kramdown syntax: https://talk.commonmark.org/t/description-list/289.

I think it's a little misleading to say that the * deflist option does not require people to learn a new syntax because it is based on <ul>. It absolutely is a new syntax, because specifying <dl> is quite different structurally from <ul>. And we would have to define that syntax in detail for people to use it reliably - work that is already done for the Kramdown syntax.

One interesting note from the CommonMark discussion I linked above is that the Kramdown syntax is awkward to parse because you have to backtrack after finding the :this is the details element. To help at least a bit with this, I think it would be fine for our purposes to implement the following restriction on <dl>:

all children of a <dl> must be pairs of <dt> and <dd> elements. That is, you can't have more than one consecutive <dt>or more than one consecutive <dd>.

That would rule out:

<dl>
  <dt>A term</dt>
  <dt>Another term</dt>
  <dd>A definition</dd>
</dl>

...as well as:

<dl>
  <dt>A term</dt>
  <dd>A definition</dd>
  <dd>Another definition</dd>
</dl>

if CommonMark does end up supporting <dl>, there's a reasonable chance that it will look like the Kramdown syntax, and there's virtually no chance it will look like any syntax we invent in this thread.

I agree that’s a pretty compelling reason (the possibility for forward compatibility).

To help at least a bit with this, I think it would be fine for our purposes to implement the following restriction on <dl>:

all children of a <dl> must be pairs of <dt> and <dd> elements. That is, you can't have more than one consecutive <dt>or more than one consecutive <dd>.

I wonder what instances (if any) we have in MDN of existing article using using more than one consecutive <dt>or more than one consecutive <dd>.

At least outside of MDN, it’s not hard to find quite legitimate cases of it — for example, I know it’s used in the markup for some specs (I think even in the HTML spec). It’s not uncommon to want to associate multiple (<dt>) terms with one shared block of text/description.

Here’s one example of adjacent-sibling <dt> from the HTML spec:

https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#the-htmlallcollection-interface%3Adom-htmlallcollection-item-2

element = collection . item(name)
collection = collection . item(name)
element = collection . namedItem(name)
collection = collection . namedItem(name)
element = collection(name)
collection = collection(name)
element = collection[name]
collection = collection[name]

Returns the item with ID or name name from the collection.

If there are multiple matching items, then an HTMLCollection object containing all those elements is returned.

Only button, form, iframe, input, map, meta, object, select, and textarea elements can have a name for the purpose of this method; their name is given by the value of their name attribute.

But that’s just one example among many such cases in the HTML spec — if you go to https://html.spec.whatwg.org and open the devtools console and do this:

document.querySelectorAll("dt + dt")

…that returns 425 nodes.

As far as instances of adjacent-sibling <dt> in existing MDN content, I ran this:

rg --multiline "</dt>\n+\s+<dt>" files/en-us/web | wc -l

…and that returns around 94 instances — though those are all concentrated in just 15 files:

files/en-us/web/accessibility/implementing_msaa_server/index.html
files/en-us/web/javascript/equality_comparisons_and_sameness/index.html
files/en-us/web/javascript/reference/global_objects/intl/pluralrules/resolvedoptions/index.html
files/en-us/web/javascript/reference/global_objects/intl/collator/resolvedoptions/index.html
files/en-us/web/javascript/reference/global_objects/intl/collator/compare/index.html
files/en-us/web/javascript/reference/global_objects/intl/numberformat/resolvedoptions/index.html
files/en-us/web/javascript/reference/global_objects/intl/datetimeformat/resolvedoptions/index.html
files/en-us/web/api/file_and_directory_entries_api/index.html
files/en-us/web/api/htmlscriptelement/index.html
files/en-us/web/http/proxy_servers_and_tunneling/proxy_auto-configuration_pac_file/index.html
files/en-us/web/html/inline_elements/index.html
files/en-us/web/css/color_value/index.html
files/en-us/web/css/align-items/index.html
files/en-us/web/css/custom-ident/index.html
files/en-us/web/css/list-style-type/index.html

https://github.com/mdn/content/blob/main/files/en-us/web/html/inline_elements/index.html#L102 has the largest number of them — but that’s an anomaly markup abuse. Not sure why it’s being used there, but it seems like it should be replaced with some other markup (regardless of the resolution of this issue).

https://github.com/mdn/content/blob/main/files/en-us/web/css/list-style-type/index.html has the next-largest number, and looks like a legitimate usage; see the rendered view at https://developer.mozilla.org/en-US/docs/Web/CSS/list-style-type#values — for example:

upper-alpha
upper-latin
  • Uppercase ASCII letters
  • E.g. A, B, C, … Z
  • upper-latin is unsupported in IE7 and earlier

There are a couple more CSS docs that have cases, and six JavaScript docs that do — including https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#when_to_use_jsxrefobject.is_versus_triple_equals:

{{jsxref("Math.atan2")}}
{{jsxref("Math.ceil")}}
{{jsxref("Math.pow")}}
{{jsxref("Math.round")}}
In some cases,it's possible for a -0 to be introduced into an expression as a return value of these methods even when no -0 exists as one of the parameters. For example, using {{jsxref("Math.pow")}} to raise {{jsxref("Infinity", "-Infinity")}} to the power of any negative, odd exponent evaluates to -0. Refer to the documentation for the individual methods.

Other examples:

After looking at the existing instances in MDN and at the instances in the HTML spec, I can’t really find any cases where it seems strictly necessary to mark them up with adjacent-sibling <dt>.

What I mean is that, in general, it seems like for any adjacent-sibling <dt> case, it’s possible to alternatively mark it up using one <dt> that holds multiple terms, separated by commas:

minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits
The values provided for these properties in the options argument or filled in as defaults. These properties are present only if neither minimumSignificantDigits nor maximumSignificantDigits was provided in the options argument.

I think a reasonable case could be made about that in fact being better for readability/usability as far as user experience.

To help at least a bit with this, I think it would be fine for our purposes to implement the following restriction on <dl>:

all children of a <dl> must be pairs of <dt> and <dd> elements. That is, you can't have more than one consecutive <dt>or more than one consecutive <dd>.

Given the above, it seems like it’d be OK/reasonable to impose such a restriction. The authoring guidance for it would seem to be pretty simple to document (e.g., “just separate multiple terms with commas on a single line, rather than putting them on separate lines”) — but ideally we’d want to be able to lint for it too. However, given the following:

One interesting note from the CommonMark discussion I linked above is that the Kramdown syntax is awkward to parse because you have to backtrack after finding the :this is the details element.

…then I’m guessing that trying to lint for it for it would run into the same problem. That is, if we could reliably parse for such cases to begin with, why would we not want to just allow them?

So I think it’d be fine to still impose the restriction even if it’s not something we could lint for.

Since there was more discussion about linting Kramdown-style lists, I spent more time trying to figure out where the sharp edges are with that (apart from parsing, which we've already acknowledged). I'm a bit troubled by them because I don't have a lot of ideas about how to sand down these edges (unlike the stuff we've considered for accepting the GFM table syntax or the solution we came up with notes and callouts). I'd really like some ideas because I don't have a lot of mitigation strategies that apply here.

CommonMark previews

In the one-level case, Kramdown style looks OK in GitHub:

Source

`callbackFn`
: Function to test for each element

`thisArg`
: Optional. Value to use as `this` when executing `callback`.

CommonMark rendering

callbackFn
: Function to test for each element

thisArg
: Optional. Value to use as this when executing callback.

The problem arises when you've got nested lists:

Source

`callbackFn`
: Function to test for each element

  `element`
  : The current element being processed in the typed array.

  `index`
  : The index of the current element being processed in the typed array.

  `array`
  : The typed array `some` was called upon.

    Here's a second paragraph.

`thisArg`
: Optional. Value to use as `this` when executing `callback`.

CommonMark rendering

callbackFn
: Function to test for each element

element
: The current element being processed in the typed array.

index
: The index of the current element being processed in the typed array.

array
: The typed array some was called upon.

Here's a second paragraph.

thisArg
: Optional. Value to use as this when executing callback.

It both flattens the list and turns subsequent blocks in the nested definitions into source blocks. This makes the preview in my editor unhelpful. As far as I can tell, there's no way I can stylesheet my way out of this problem. All my solutions to this problem are kinda poor and I'd like to hear ideas on how to counter this. It's really frustrating to me that there's no gentle upgrade path for opting into this one Kramdown feature (especially since we're not using Kramdown generally).

Conflict with Prettier

While experimenting, I also ran into this problem: Prettier _really_ wants to wreck these lists (turns out I have Prettier formatting Markdown files by default). Over in https://github.com/mdn/content/issues/4325#issuecomment-827836636, we talked about the possibility of using Prettier to make working with GFM tables a bit nicer. This syntax puts a roadblock up for that. The easiest solution is to wrap those sections with Prettier opt-outs:

<!-- prettier-ignore-start -->
`callbackFn`
: Function to test for each element, taking three arguments.

  A second paragraph.

`thisArg`
: Optional. Value to use as `this` when executing `callback`.
<!-- prettier-ignore-end -->

Though that adds a weird, extra obligation for using these lists. (Prettier does support plugins, but it's not yet clear to me how easy it is to wrap the existing behavior and apply our special case.)

Daniel, Gregor and I just had a discussion about this issue, which I'm going to capture in this comment.

The concerns Daniel raised in https://github.com/mdn/content/issues/4367#issuecomment-836990164 are significant, especially the one about Prettier. What's worse is that they are symptoms of a general problem with adopting a "CommonMark-unfriendly" syntax: so much of the tooling tends to want CommonMark, that we're likely to encounter versions of this problem again, even if it were practical to fix the issue with Prettier.

So we should consider a principle that we try to stay "CommonMark-friendly" even when we are extending the CommonMark/GFM syntax, and that means reconsidering something like Daniel's deflist proposal in https://github.com/mdn/content/issues/4367#issuecomment-827553513.

The main reason to want to use Kramdown syntax would be that it's well-specified and has working implementations, so there's good reason to believe that the edge cases have been worked out. I'm a bit anxious to invent a new syntax and have to go through that. But perhaps we can make this less of a problem if we support a limited version of <dl>.

If we think we can get away with a syntax in which a <dl> consists of pairs of <dt>/<dd> elements (for which see Mike's https://github.com/mdn/content/issues/4367#issuecomment-834986190), then it's much easier to spec and to write. At that point we might even consider that the * deflist magic word is over-specifying it, and we could even signal a <dl> using syntax like:

* `param1`
* : My description of param 1
* `param2`
* : My description of param 2

  It can have multiple paragraphs.

      ```js
      const thing = 1;
      ```

...that is, interpret a <ul> consisting of an even number of items, where even-numbered items start with ":", as a <dl>.

Or maybe for nicer GitHub formatting, something like:

* `param1`
    * : My description of param 1

* `param2`
    * : My description of param 2

      It can have multiple paragraphs, and code blocks too:

      ```js
      const thing = 1;
      ```

...which would render in GitHub like:


  • param1

    • : My description of param 1
  • param2

    • : My description of param 2

      It can have multiple paragraphs, and code blocks too:

      const thing = 1;
      

If authors really need full <dl> support, which as https://github.com/mdn/content/issues/4367#issuecomment-834986190 shows is really rare on MDN, they can always resort to HTML, as we already accept for tables.

FWIW I really like the "nicer GitHub formatting" above https://github.com/mdn/content/issues/4367#issuecomment-840008658

Other than the colon, this is how I represent definition lists in markdown normally.

I have had a go at writing this up -> https://github.com/mdn/content/pull/4987.

Was this page helpful?
0 / 5 - 0 ratings