@Card directive

Hi all.

I'd like to pitch a simple new DocC directive called @Card which can be used
to group and highlight related blocks of content within an article.

Proposal

In its most basic form, the card simply wraps a number of markdown content
blocks to present a unified container, rendered with a simple "card" background.

Example:

@Card {
	Hello

	World
}

With the introduction of a thematic break (or horizontal rule), the card
content can be organized into distinct header/body sections that could be
rendered with different background colors.

Example:

@Card {
	### This is a heading

	More heading content

	---

	This content is the main body of the card.

	Here is some more body content.
}

Each section of the card could compose other kinds of markdown syntax or DocC
directives, so authors are empowered to use it in creative ways that best suit
their content. I expect this new presentation construct could be an easy way
to elevate and group related components of an article in ways that aren't
possible with plain markdown formatting constructs.

Example:

Notes

  • only the first horizontal rule would be considered to partition the head/body
    sections of a card--subsequent hr tokens would just be rendered as normal
    horizontal rules within the body section of the card

Alternatives considered

This proposal shares a lot of similarities to the existing concept of "asides",
and it could be argued that there is no need for a distinct new syntax and style
of rendering for this type of content.

Personally, I see this new card presentation as providing additional flexibility
for authors without replacing that existing concept. The grouped section doesn't
require a header to render and if one is provided, it can contain nested blocks
of content as opposed to just being a simple header string. Also, the way that
it is presented in renderers would be more direct as opposed to the way that
asides are meant to be rendered in a slightly more indirect manner when compared
to surrounding article content. Longer form card content would also be slightly
easier to write since the blockquote syntax for asides needs to prepend every
line of markdown (although I see this as a relatively minor issue).

While similar, I believe that it makes sense for "cards" and "asides" to live
in the same world and it benefits authors to have the flexibility of utilizing
whichever makes more sense for their use case.

4 Likes

I have implemented the proposed changes with the following PRs if you want to try it out:

Super cool @marcus_ortiz - thanks for sharing the PRs - I'm looking forward to exploring it a bit. In the meantime - since you probably already know this off the top of your head:

  • does this provide an "aside like mechanism" that can host a bulleted or numbered list?
  • Can these be nested?
  • Is there any separate presentation control (specifically for background color) for a card, or is it meant to only semantically organize content vs. potentially highlight off a different background?
  • Does a card always span the page visually?

And last - could you share the markdown content that matches with the third example (with the code block to the right of the narrative text?)

  • does this provide an "aside like mechanism" that can host a bulleted or numbered list?

Yes. The contents of the card could be any DocC block content, including lists, or even other block directives like @Row/@Column, etc. The third example shows this, and the code for it will help demonstrate how it works (see below).

  • Can these be nested?

Technically yes, although I don't know that they would necessarily look good. If we want this to be a valid use case, I may need to modify the CSS to better alternate background colors, although I expect we may not want to support cards within cards (maybe I should add a warning for this).

  • Is there any separate presentation control (specifically for background color) for a card, or is it meant to only semantically organize content vs. potentially highlight off a different background?

The background colors right now use the default fill-secondary and fill-tertiary colors from Swift-DocC-Render. These can be customized with the experimental theme-settings feature.

If we want to be able to customize these colors independently from the default secondary/tertiary colors, I may need to add an additional CSS property to make sure that this is possible, even if the defaults use the same.

  • Does a card always span the page visually?

I'm not entirely clear what you're referring to here—do you mean if the card always spans the full horizontal width? They would as coded in the initial PRs, although you could potentially use outer row/column directives in the content to create a smaller width layout for a card without any modifications to the code.

And last - could you share the markdown content that matches with the third example (with the code block to the right of the narrative text?)

This example just uses @Row and @Column within an example @Card :)

@Card {
  ### Fast

  Build with speed and performance.

  ---

  @Row(numberOfColumns: 10) {
    @Column(size: 3) {
      Swift meets the most performance-critical needs,
      while allowing your code to remain expressive and approachable.

      Swift compiles directly to native code and provides predictable memory management.
    }

    @Column(size: 7) {
      ```swift
      // Vectorized check that a utf8 buffer is all ASCII
      func isASCII(utf8: Span<SIMD16<UInt8>>) -> Bool {
        // combine all the code units into a single entry
        utf8.indices.reduce(into: SIMD16()) {
          // fold each set of code units into the result
          $0 |= utf8[$1]
        }
        // check that every entry is in the ASCII range
        .max() < 0x80
      }
      ```
    }
  }

  [Find out more](https://swift.org)
}
2 Likes

Awesome example, thank you @marcus_ortiz !

1 Like

Thank you for posting this interesting pitch. I have a number of questions that I'll group into four categories: "use cases", "where it's supported", "syntax", and "JSON representation".

Use cases

I feel that what's mostly missing from this pitch is a description of what problem this is solving. I'm hoping that by talking about the use cases, we can find and formulate what that problem is. To that end;

Can you give some examples of what you think that developers would use this @Card directive for?


Regarding the first "Hello World" example, that doesn't have a header. To me this looks quite similar to an aside (except that it doesn't have a "note"/"warning" title). Can you think of any examples where developers would go for a @Card directive without a header instead of an aside? Alternatively, if DocC were to add documentation to help developers decide between an aside and a @Card directive without a header; are there any key guiding questions (for the documentation to ask of the developer) that you can think of that would help steer them in one direction or the other?


Regarding the third "Build with speed and performance" example. I know that that specific text and code comes from the swift.org landing page but if we ignore the specific text and content;

What types of pages do you think are most likely to use a long @Card directive like that—with both a titled header, a couple of paragraphs of text, and maybe a code block or an image—and how does that card content fit in with the text before and after it on the rendered page?

I'm thinking of this tip from DocC's documentation about writing asides (quoted below) and how some of those same issues of interrupting the flow of the surrounding text and looking more visually heavy could apply to long Card directives as well:

If you have much information to provide about a subtopic, consider using a subsection rather than a multi-paragraph aside. This can help with the flow of the text and make the information appear less visually heavy on the page.

Assuming that cards that cover subtopics that are too long would eventually be a better fit for a subsection; where do you think that the balance is between a quick callout in an aside, a medium-length(?) Card directive, and a full subsection?


Do you think that developers will convert some of their existing aides into @Card directives, and if so what do you think would be the primary reason to do so?

For example, I find it a bit ironic that in this pitch so far

@Card { 
    To be, or not to be
}

would be visually represented closer to how developers expect a block quote to be displayed than how > To be, or not to be is displayed today.

I would consider it a failure if people switch to using @Card directives for quotes and other callouts as a workaround to avoid displaying the aside kind ("Note", "Warning", etc.). I wonder if the use cases for the header-less @Card directives could really be an indication of use cases where developer would like to avoid displaying the aside kind on the rendered page.

Similarly, I wonder if there are use cases where a developer would want to display a heading—with a slightly more emphasized background color—with a title and summary in an aside that for examples warns about one or more situations to be careful about (a warning aside) or that provides recommendations (a tip aside) or similar.

Where it's supported

Have I understood correctly that this first sentence (emphasis mine):

[...] which can be used to group and highlight related blocks of content within an article.

is proposing that DocC will only support this new @Card directive in articles and that it won't support it in either Tutorial documentation or in symbol documentation (regardless if the content comes from an in-source documentation comment or from a documentation extension file)?

Syntax

The questions I have about the syntax mostly relate to the possible use cases and the potential overlap with asides. Most of those questions in one way or another lead to the broader question: have you considered extending asides with these same capabilities (not displaying the aside name and having an optional heading)? If that was a consideration, can you describe why the proposed Card directive solves "the problem" (which the use cases above hopefully helped formalize) better?

For example, if DocC supported asides that don't display the aside kind; do you think that there would be the same need to support header-less @Card directives?

Alternatively, if DocC supported optional headers in asides—and hypothetically the @Card directive as well—when do you think a developer would reach for one or the other?


Regardless of the broader syntax discussion (a new directive or enhanced asides); one detail that struck me as a bit odd in the examples in this pitch was that both examples with a heading use a level-3 heading. Can you share some details about why they use that specific heading level? Would a level-1 heading appear too large on the page? Part of me feels that this makes the directive scope feels less isolated from the content around it but at the same time I can appreciate the simplicity of keeping the element formatted the same both inside and outside the card scope.

Unless I've misunderstood the JSON specification; it doesn't support formatted heading text. If that's correct, have you considered using a directive argument for the card's title/heading? That could avoid some confusion around what level of heading developers should choose for their title.

@Card(title: "This is a heading") {
	More heading content

	---

	This content is the main body of the card.

	Here is some more body content.
}

A similar concept could be expressed in an aside (using some hypothetical straw man syntax):

> Card: This is a heading
>
> More heading content
>
> ---
>
> This content is the main body of the card.
>
> Here is some more body content.

That said, if some developers have a reason to use very long titles that would look too large as a level-3 heading; perhaps it's worthwhile to maintain the flexibility of allowing them to use a level-4 or level-5 heading for the title of that card.

JSON representation

In addition to the developer facing syntax, the other piece that's really difficult to change once it's merged is the way that the page information is represented in the JSON that DocC creates and DocC Render reads. Can you share how you think that this card content should be represented in the JSON?

Also, can you think of any possible future additions to the @Card directive that would require a change to that JSON representation? If there are any remotely possible enhancements then it would be good to ensure that we can make those changes in the future without requiring breaking changes to the JSON representation. For example, what if in the future cards gained a (third) footer section?

1 Like

Thanks for your thorough feedback David. I'll do my best to respond directly to the questions you bring up, although it was a big post, so forgive me if I miss anything.

  • Calling attention to a grouped section of content
  • Providing visually distinguishable blocks for heading content that introduces
    this grouped content

As you point out, I think the use cases are similar to the use cases of asides while providing some more flexibility for layout of the heading area and alllowing for ways of directly highlighting content sections whereas asides are more intended for content that is indirectly related to the main document content and have an existing way they are expected to be rendered.

I think it helps better call attention to specific blocks of content that might otherwise get lost in a wall of text between subsection headings.

I think you describe it well where there is a balance between the amount of content vs the amount of visual noise. An aside is great for adding a short, indirect note about a topic. Subsections are useful for labeling sections of content and creating an outline/hierarchy. I expect @Card can be useful at times at better visually highlighting and grouping key sections of content when an aside or subheading doesn't fit very well for that purpose.

I think it's possible, but I don't know for sure. I think this could happen in places where developers may have used asides for content they want to highlight but aren't satisfied with the way that asides are purposefully rendered more indirectly than they would like for the content being presented, or if they would like more flexibility on how the content is labeled.

That's a great point. I'm not 100% confident that a @Card without a heading section is entirely useful for this reason, although I agree we should support blockquotes regardless. Mostly I have left the head section for cards as optional purely for flexibility reasons, but I could see an argument for making them be required.

Providing a semantic distinction would be one reason--just because they look similar doesn't mean that it's not useful to have distinct semantic HTML elements for quoted text vs highlighted content, even if they end up being displayed in similar manners on the resulting webpage.

Sorry, I think my wording just caused the confusion here. By the term "article", I was just loosely referring to documentation content. I don't see any strict reason for disallowing this directive for symbol pages or other page types like tutorials.

Yes, this was the focus of the "Alternatives considered" section.

Essentially I think this boils down to wanting to give developers the most flexibility. Rather than trying to fit the current aside styling/layout to all use cases or trying to workaround blockquote/aside syntax, I think it makes sense to provide a new primitive where developers have more control over how this kind of content can be displayed without impacting the existing aside styling and use cases.

The clearest scenario would be when a developer wants more flexibility over how the heading is rendered and what content goes in the head section. For example, you could use a simple paragraph in the head section if using a heading is calling too much attention. Or maybe you want the heading to be a simple image instead of text at all? The @Card approach gives more flexibility in this case, although I don't expect cards to ever replace or be more commonly used than asides.

I think it's a fairly realistic example of a good use case since it might be common to use a card inside of a subsection that already is using an h2 and the page itself already has an h1. I don't see a specific reason to limit the possible heading levels in the same way that we allow developers to add h1s to their pages, even though web content shouldn't have more than a single h1. The renderer could always enforce a reasonable font-size to try to limit issues that arise with using larger heading sizes. It's also just an example, and there's nothing forcing a developer to even use a heading in this head section at all.

This is true for DocC heading syntax in general, although I see that as a unnecessary limitation that should ideally be fixed in the future.

More importantly, the head section for the card doesn't require that heading syntax even be used. In the interest of flexibility, this section could contain any kind of markdown block content, like a simple paragraph or maybe an image instead of any text at all. For that reason, I think using a simple string directive argument would be limiting.

I'm not completely opposed to an alternative syntax, although I do think that the block directive syntax is easier to write than the blockquote syntax and makes it more clear to visually parse the card content in the markdown in the same way that it is visually highlighted in the rendered page.

Here is my expectation for the example in my post:

{
  "type": "card",
  "head": [
    {
      "type": "heading",
      "level": 3,
      "text": "This is a heading"
    },
    {
      "type": "paragraph",
      "inlineContent": [
        {
          "type": "text",
          "text": "More heading content"
        }
      ]
    }
  ],
  "content": [
    {
      "type": "paragraph",
      "inlineContent": [
        {
          "type": "text",
          "text": "This content is the main body of the card."
        }
      ]
    },
    {
      "type": "paragraph",
      "inlineContent": [
        {
          "type": "text",
          "text": "Here is some more body content."
        }
      ]
    }
  ]
}

The head and content fields are just dynamic arrays of block content that renderers can choose to display in distinct ways.

I'm not expecting further changes that would require JSON changes, but we could potentially add more keys to this structure if we wanted to add other visually distinct rendering for other kinds of content in the future.

I don't think it would make sense to have a single, multi-dimensional array of block arrays, because I don't anticipate supporting a row-like rendering for something like a hypothetical footer section.

My key takeaway from your first three inline replies (about use cases) is that the proposed @Card directive primarily aims to solve same problem / use case as an aside does today. If I compare how your replies describes that use case:

Calling attention to a grouped section of content

[...] call attention to specific blocks of content [...]

with how DocC's documentation about asides describes that use case:

[...] get the reader’s attention to provide additional advice, or to warn them about common errors or requisite configuration.

I find these use cases to be the same in essence, and almost the same in phrasing as well; drawing attention to some particular content. If you don't think these are the same use case I would appreciate some clarification on how you find these use cases to be different.

Note that DocC supports custom aside titles so an aside doesn't have to be one of the predefined kinds (note, important, tip, warnings, experiment). Developers can use asides for any type of callout. For example, DocC uses custom aside titles to call attention to differences in behavior or capabilities across versions.


The second piece—as far as I understand it—of this pitch is the optional header, or as you phrased it in your replies above:

Providing visually distinguishable blocks for heading content that introduces
this grouped content

[...] providing some more flexibility for layout of the heading area.

I view this as more of a capability, in search of a use case, than a use case in itself but for the sake of discussion I'll consider it a worthwhile capability that we want to add.

If I put those two pieces together—and phrase them in abstract terms (largely based on how they're phrased in your replies above)—I would summarize that this proposal wants to add these two capabilities for developers to use in their documentation:

  • Call attention to a block of content on the page
  • Provide an optional flexible heading that can introduce that block of content

In my mind, the first piece is already solved by asides today. Asides can contain both multiple paragraphs of text, images, and code blocks. I don't see sufficiently distinct use cases being presented to warrant a new solution with its own user-facing syntax for this.

Asides doesn't have a distinct heading area today—and neither does the @Card directive exist today—but I haven't really seen any arguments for why asides couldn't or shouldn't have an optional heading area. It could even use the same thematic break separator syntax from this proposal, offering complete flexibility of what the developer choses to put in the heading area, what level of heading fits best with their content, and all of the other benefits (and drawbacks) of the proposed thematic break separator syntax.

That, to me, would feel like a more natural and sequential evolution of the syntax that build on what's already there and minimizes syntactic fragmentation (by not creating two different syntaxes for the same problem).


If you disagree that these are the same problem / use case, it would help if you could provide more specific use case examples that distinguishes the need to call out the block of content for an aside and then need to call out a block of content for something else. As the person who is proposing this feature; I consider that responsibility to lie on you.

In my opinion, without demonstrating that the problem being solved is sufficiently different,
the argument that this is a new capability and can introduce new syntax rather than build on existing syntax is diminished which IMO warrants higher scrutiny for deviating from the existing syntax (increasing syntactic fragmentation) for that same problem.

A few additional inline replies about more detailed questions / subtopics:

We haven't really discussed how an alternative syntax could opt in to a card "appearance". If that's explicit syntax and explicitly encoded in the JSON that DocC outputs, I would imagine that DocC Render could still use distinct semantic HTML elements for cards and other asides.

Otherwise, if every type of aside can have a header area, wouldn't we be able to get almost all of the benefit from using different semantic HTML elements based on the presence of that heading area?

I'm not sure that I understand what flexibility and what workarounds you're referring to here. As far as I understand developers would have all the same flexibility in an aside. Unless I'm missing something there are only two capabilities of the proposed syntax:

  • Defining a scope that contains some content
  • Dividing that content into two parts based on a separator.

A directive is one syntax for defining a scope of inner content. An aside if another syntax for defining a scope of inner content. I'm not aware of any differences in capability—for defining a scope of inner content—between those two syntaxes.

Asides don't have syntax today for dividing the content into a header section and a body section—but neither does a @Card directive exist today—but I would imagine that the proposed thematic break separator syntax would work equally well in an aside as in a directive.

Assuming that's correct; is there any reason why developers would have less flexibility with an aside syntax like below? Can you clarify what syntax it is that developers would need to work around?

> ### This is a heading
>
> More heading content
>
> ---
>
> This content is the main body of the card.
>
> Here is some more body content.

If I try the example above in DocC today, without any new features, I could make an argument that, to some limited extent, it accomplishes both the "call attention" goal by placing the content in a container with a background and the "visually distinguish the header" goal from the thematic break.

I'd be the first to say that it doesn't look polished. The header could certainly be more visually distinguished (and the little "Note" label has limited value when there's a header) but it does illustrate that it's somewhat possible to author such content already. Because of this, one could argue that the biggest impact of this proposal the refined visual presentation of such a callout and its header section.

Unless there's something I'm missing, this is all about the syntax for dividing the container's content into a header section and a body section. Like I said above, it seems to me—unless I'm missing something—that the proposed thematic break separator syntax would work equally well in both a directive and in an aside, so I would assume that syntax would have the same capabilities regardless of the container it's in.

There are three situations that I'm trying to avoid here:

  • Rushing a syntax that we'll have a hard time backing out of.

    Even if we reserve the right to make breaking syntax changes as long as this feature is considered experimental, doing so creates churn that's best avoided. Ideally, we would only make breaking syntax changes if there's strong feedback from developers who try out a feature in the release(s) where it's available as an experimental preview.

  • Missing important improvements or tie-ins with other features that risk being overlooked.

  • Introducing unnecessary syntactical fragmentation from having competing solutions to the same problem.

    This can both make developers have to decipher which solution is more appropriate on a case-by-case basis, make it harder to write good documentation that guide developers towards the right feature for a given problem, and can result in feature duplication and code duplication over time.

I hope that you can agree that taking the time to carefully consider the long term impacts before settling on a syntax is a worthwhile pursuit.

Those are all great points. Thanks David.

I think the key takeaway is that I should explore if it makes sense to simply augment the existing syntax used for aside elements to provide the additional capabilities for custom header content and sectioning without the need for having a separate directive that requires the overhead for developers in terms of deciding which element to use.

Briefly looking into the current aside syntax, it does seem that there is a limitation preventing nested directives from being appropriately parsed in the body of the aside—but, I think that's not an intentional limitation, so I can look into resolving this as part of my exploration.

1 Like