Styling Components in Doenet
This guide is a set of practical recipes for controlling how Doenet components look: choosing a predefined style, tweaking one setting at a time, and redefining the styles themselves. It assumes you already know the basics of writing DoenetML — tags, attributes, properties, and children.
Want the reasoning behind these recipes — why you choose a style number instead of writing a color, and why colors work the way they do? See Styling, meaning, and accessibility. This guide focuses on how; that page explains why.
We build up from the simplest tool to the most precise:
- picking one of the predefined styles with
styleNumber, - tweaking individual settings with style attributes on a component,
- and finally redefining the styles themselves with
<styleDefinition>.
Use a predefined style
Doenet comes with six predefined styles, numbered 1 through 6. Every component starts out using style number 1. To switch a component to a different predefined style, set its styleNumber attribute.
The example below draws the same point six times, once in each predefined style. Notice that each style has its own color and its own marker shape.
You don’t have to memorize what each style number looks like — the Doenet editor will tell you. The example above is a live editor, and along its bottom edge is a context-help panel (open by default, on the Context tab) that describes whatever your cursor is touching.
Try it: click on the styleNumber="2" of the second point. The panel updates to a Resolved style listing for style 2. Because a point is drawn with a marker, it shows the marker settings for that style — among them markerColor #D4042D (named red), markerStyle square, markerSize 5, and markerFilled true. In other words, style 2 draws a point as a red, square, filled marker. Click on a different point’s styleNumber and the panel re-reads off the settings for that style.
The panel lists each color twice: once for normal (light) mode and once for dark mode (the …DarkMode entries). You can ignore the dark-mode entries for now — dark mode is not yet implemented in Doenet, so only the light-mode colors take effect.
Wondering why you pick a style number at all, instead of just writing a color? That is a deliberate design choice about meaning and accessibility — see Styling, meaning, and accessibility.
Style several components at once
A component that doesn’t set its own styleNumber inherits it from the nearest container that does — a <graph>, a <section>, or a <group>. So you can gather several components into a <group>, set styleNumber once on the group, and every member follows along unless it sets its own.
The two points inside the <group> pick up style 4 from it. The third point sits outside the group, so it keeps the default style 1 — the group’s styleNumber reaches only its own members.
Color text and math
Style numbers also set the color of text and math, so you can color text just by choosing a style number — no other setup required. To color a phrase within a sentence, wrap it in a <text> with the style number you want.
styleNumber applies to the text- and math-displaying components, such as <text>, <m>, and <math>.
Show a region’s fill
A region — a <circle>, <rectangle>, <polygon>, or other closed shape — is unfilled by default, so it shows only its outline and the style’s fill color is invisible. Set filled="true" to fill the interior so the fill color shows.
All three components use style 2, but each expresses its color differently: the point as a marker, the line as a stroke, and the circle as a fill (visible only because of filled="true").
Override one setting at a time
The predefined styles bundle several settings together. Often you want to keep a style but adjust just one thing — a thicker line, a dashed line, a hollow point. You can set many of these directly as attributes on a graphical component.
The attributes you can set depend on the kind of component:
- on lines, line segments, rays, and vectors:
lineWidthandlineStyle(solid,dashed, ordotted); - on points:
markerStyle(circle,square,triangle,diamond,cross,plus, …),markerSize, andmarkerFilled; - on regions (circle, polygon, rectangle, curve): the line attributes above, plus
fillOpacity.
Setting an attribute that doesn’t apply to a component — lineWidth on a <point>, say — is an error, which the editor will flag.
Line width and dash style
Each segment keeps the color of its style (the first two are the default blue; the third is style 2’s red) while overriding the width and dash.
Marker shape, size, and fill
markerFilled="false" gives an open (hollow) marker instead of a filled one.
When an open marker — or any visual difference — is meant to carry meaning, such as an excluded interval endpoint, reach for a semantic component like <endpoint> rather than styling a plain point. See Mark meaning with a semantic component below.
Fill opacity
Notice that none of the attributes in this section is a color. There is no lineColor, markerColor, or fillColor attribute you can place on a component — the only way to change a color is to redefine the style, covered next. (For the reasoning, see Why you can’t set a color directly on a component.)
Mark meaning with a semantic component
Styling changes how something looks; it does not record what something means. So when a visual difference carries meaning — an excluded interval endpoint, an unstable equilibrium — reach for a component built for that meaning instead of imitating it with a style.
Compare a plain point made hollow with markerFilled="false" to an <endpoint>. Both render as an open marker, but only the <endpoint> records that the endpoint is excluded. A default <endpoint> is closed (included); add the open attribute to make it open (excluded):
A semantic component owns the part of its appearance that carries its meaning, so an <endpoint> takes open-vs-closed from open, not from markerFilled. The same pattern applies to <equilibriumPoint>, <equilibriumLine>, and <equilibriumCurve>, which take stable-vs-unstable from stable — a stable equilibrium draws closed (or solid), an unstable one open (or dashed):
You can still style these components in the ordinary ways — set their styleNumber, line width, marker size, and so on — they simply own the one aspect of appearance that encodes their meaning. For why this matters, and why it is the more accessible choice, see Some distinctions have a name: semantic components.
Redefine a style (and change colors)
The six predefined styles are themselves style definitions, and you can redefine them. A <styleDefinition> placed at the top of your document changes a style number everywhere it is used. This is also the only way to change a color.
A <styleDefinition> names the styleNumber it applies to and then lists the settings to change. Here we redefine style 1 to be green across the board — its line color, its marker color, and its fill color:
(A <styleDefinition> produces no visible output of its own, so it can sit directly in your document — it does not need to go inside a <setup> block.)
None of these components set styleNumber, so they all use style 1 — which is now green. The three components draw their color from three different settings: a point uses markerColor, a line uses lineColor, and a filled region uses fillColor. A style definition can set any of those, along with non-color settings such as lineWidth, lineStyle, markerStyle, markerSize, and fillOpacity. It only changes the settings you list; everything else about that style number keeps its previous value.
The context-help panel keeps up with your redefinition. Click on the styleNumber="1" inside the <styleDefinition> (or on any of the components): the Resolved style listing now reports lineColor, markerColor, and fillColor as green. The panel always describes what will actually be drawn, so it is the quickest way to confirm a change took effect.
Definitions set defaults; component attributes win. You can also use a <styleDefinition> to set defaults for the non-color settings — for example, to make every style-2 line thick. But if a particular component also sets that setting as an attribute, the component’s attribute takes precedence. (Color is the exception: it comes only from the definition and cannot be overridden on the component.)
Both segments are red — the color comes from the definition. The first segment is thick (width 5, from the definition); the second overrides the width to 1 with its own attribute.
Scope a style to a section
A <styleDefinition> doesn’t have to apply to the whole document. Place it inside a <section> and it applies only within that section; everything outside is unaffected, and nested sections can override their parent’s definitions.
Both points use style 1 with no styleNumber attribute, but the first is purple (the section redefined style 1) while the second keeps the document-wide default.
Summary
- Every component starts in style 1. Switch to another predefined style with
styleNumber(1–6); the editor’s context help describes each one. - A component inherits
styleNumberfrom its nearest container, so you can style several components at once. - What a style controls depends on the component: markers for points, strokes for lines, strokes and fills for regions. Use
filled="true"to see a region’s fill color. - Override non-color settings per component with attributes like
lineWidth,lineStyle,markerStyle,markerSize,markerFilled, andfillOpacity— for appearance, not to carry meaning. - When a difference carries meaning (an excluded endpoint, an unstable equilibrium), use a semantic component like
<endpoint>rather than styling a plain one. - Change colors — and redefine any style number — with
<styleDefinition>, at the document level or scoped to a section.
For the reasoning behind all of this — why style numbers exist and what that means for accessibility — read Styling, meaning, and accessibility.