Allow tags to accept multiple sets of child nodes via slots #342
rpaul-stripe
started this conversation in
RFP
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Introduction
This proposal describes a new feature called slots, which make it possible to define a custom tag that accepts multiple sets of children. Slots can also be used as an alternative to attributes in cases where you want to accept arbitrary Markdoc content instead of a conventional attribute type.
Imagine that you have a custom tag called
card
that displays a card with a heading and a body. There are several different ways to model this in Markdoc, each with its own set of trade-offs. If you make the tag accept aheading
string attribute, for example, you would not be able to include arbitrary formatting in the heading content. You could instead create a separate tag calledcard-heading
, but it can be difficult to enforce correct usage when you expect tags to be nested in specific ways.Instead of using an attribute or a nested tag, you can add a
heading
slot to thecard
tag:Schema
Slots are defined alongside attributes in a custom tag or node schema. The schema object can have the following two optional properties:
required
: aboolean
value that indicates whether the slot must be used inside of the tag. When this property is set totrue
, the validator will display an error message if the named slot is not used.render
: aboolean
or astring
value that indicates how the slot should be processed by Markdoc's default attribute transformer. By default, the slot content is transformed and becomes an attribute of the same name on the parent tag in the render tree.render
to astring
overrides the attribute name used in the output.render
tofalse
causes the slot to be ignored, which can be useful when you want to handle the slot content manually in a tag transform function.It is possible to declare a slot and an attribute with the same name. In cases where both are present in the content, the slot value is the one that appears in the render tree. If you want to preserve both values, you can use the
render
property to make one of them output with a different name.Usage
Slots are identified during parsing. In order to use slots, you must enable the feature by passing the
slots
parameter to the Markdoc parser:When this setting is not enabled, the parser treats a
slot
tag the way that it treats every other tag. Making this feature opt-in prevents possible collisions in environments that may already have a user-defined tag that happens to be calledslot
.The slot content is stored in a
slots
property on thenode
object. The slots are keyed by name: you can, for example, access theheading
slot vianode.slots.heading
. When the parser encounters aslot
tag with a valid name, it appends it to the parent node'sslots
property instead of appending it to the children.If the
slot
tag does not have a primary attribute value or has a primary attribute value that is not a string, theslot
tag is appended to the node's children instead of being added to theslots
property.The
node.walk()
iterator function automatically detects when a node has slots attached. While iterating over an AST node, it yields each of the node's slots before yielding the node's children. This means that AST analysis or transforms that rely onwalk()
will generally function as expected with slotted content. Other kinds of AST analysis may need to explicitly account for slots.Rendering
In the
card
example, when using Markdoc's React renderer, theCard
React component receives aheading
prop that contains rendered React elements representing the content nested inside of theheading
slot.When using the HTML renderer, you might want to define a custom
transform
function on thecard
tag and incorporate the slot content into the output:Overriding the slot tag
During the transform step, the content of the slot is transformed using the
slot
tag implementation. By default, this tag simply passes through its content, returning an array of render tree nodes representing the slot's children. You can override this behavior by passing your ownslot
tag into the config during transform:You can also use this approach to add your own custom attributes to the
slot
tag. Note, however, that the slot name must be theprimary
attribute.Validation
The Markdoc validator checks to make sure that slots are used in conformance with the schema definition. The following validation errors arise from incorrect use of slots:
slot-undefined
: a slot exists in the content that isn't explicitly declared in the schemaslot-missing-required
: the content is missing a slot that is declared withrequired: true
in the schemaattribute-value-invalid
: a slot tag in the content is either missing a name or uses a non-string value for the nameBeta Was this translation helpful? Give feedback.
All reactions