@markuplint/html-spec 4.16.0 → 4.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.ja.md +285 -0
- package/ARCHITECTURE.md +196 -0
- package/CHANGELOG.md +26 -3
- package/README.md +11 -259
- package/SKILL.md +358 -0
- package/docs/build-pipeline.ja.md +170 -0
- package/docs/build-pipeline.md +171 -0
- package/docs/element-spec-format.ja.md +952 -0
- package/docs/element-spec-format.md +521 -0
- package/docs/maintenance.ja.md +359 -0
- package/docs/maintenance.md +397 -0
- package/index.json +370 -42
- package/package.json +5 -5
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
# Element Specification Format
|
|
2
|
+
|
|
3
|
+
This document is a comprehensive reference for the JSON element specification file format
|
|
4
|
+
used by `@markuplint/html-spec`. It covers file naming conventions, the full structure of
|
|
5
|
+
element spec files, content model patterns, attribute definitions, ARIA integration, and
|
|
6
|
+
the shared common files.
|
|
7
|
+
|
|
8
|
+
## File Naming Conventions
|
|
9
|
+
|
|
10
|
+
### HTML Elements
|
|
11
|
+
|
|
12
|
+
Pattern: `src/spec.<tag>.json` (e.g., `spec.div.json`, `spec.table.json`, `spec.input.json`)
|
|
13
|
+
|
|
14
|
+
### SVG Elements
|
|
15
|
+
|
|
16
|
+
Pattern: `src/spec.svg_<local>.json` (e.g., `spec.svg_text.json`, `spec.svg_circle.json`)
|
|
17
|
+
|
|
18
|
+
The local name preserves case (`svg_animateMotion.json`). The element name is inferred
|
|
19
|
+
at runtime as `svg:<local>` (e.g., `svg:text`, `svg:clipPath`).
|
|
20
|
+
|
|
21
|
+
### Common Files
|
|
22
|
+
|
|
23
|
+
- `spec-common.attributes.json` -- Global attribute category definitions (19 categories)
|
|
24
|
+
- `spec-common.contents.json` -- Content model category macros
|
|
25
|
+
|
|
26
|
+
### JSON with Comments
|
|
27
|
+
|
|
28
|
+
All spec files support JavaScript-style comments (`//` and `/* */`) via `strip-json-comments`.
|
|
29
|
+
Use comments to link to specification URLs at the top of each file:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
// https://html.spec.whatwg.org/multipage/grouping-content.html#the-p-element
|
|
33
|
+
// https://www.w3.org/TR/html-aria/#el-p
|
|
34
|
+
{ ... }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Top-Level Structure
|
|
38
|
+
|
|
39
|
+
Each element spec file is a JSON object with four required top-level fields:
|
|
40
|
+
|
|
41
|
+
| Field | Type | Description |
|
|
42
|
+
| -------------- | ------ | -------------------------------------- |
|
|
43
|
+
| `contentModel` | object | Permitted content rules |
|
|
44
|
+
| `globalAttrs` | object | Global attribute category inclusions |
|
|
45
|
+
| `attributes` | object | Element-specific attribute definitions |
|
|
46
|
+
| `aria` | object | ARIA role and property integration |
|
|
47
|
+
|
|
48
|
+
An optional `omission` field may appear in the compiled `index.json` output. It is set
|
|
49
|
+
from MDN data during the build process and is not authored manually in spec files.
|
|
50
|
+
|
|
51
|
+
## Content Model
|
|
52
|
+
|
|
53
|
+
The `contentModel` object defines what children an element may contain.
|
|
54
|
+
|
|
55
|
+
### `contentModel.contents`
|
|
56
|
+
|
|
57
|
+
Accepts one of three forms:
|
|
58
|
+
|
|
59
|
+
- `false` -- Void element; no children allowed (e.g., `<input>`, `<br>`)
|
|
60
|
+
- `true` -- Any content allowed (used for certain obsolete elements)
|
|
61
|
+
- An array of content model patterns (see below)
|
|
62
|
+
|
|
63
|
+
### `contentModel.conditional`
|
|
64
|
+
|
|
65
|
+
An optional array of context-dependent content model overrides. Each entry has a
|
|
66
|
+
`condition` (CSS selector) and `contents` (array of patterns). When matched, the
|
|
67
|
+
conditional content model replaces the default:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
"conditional": [{
|
|
71
|
+
"condition": "dl > div",
|
|
72
|
+
"contents": [{
|
|
73
|
+
"oneOrMore": [
|
|
74
|
+
{ "zeroOrMore": ":model(script-supporting)" },
|
|
75
|
+
{ "oneOrMore": "dt" },
|
|
76
|
+
{ "zeroOrMore": ":model(script-supporting)" },
|
|
77
|
+
{ "oneOrMore": "dd" },
|
|
78
|
+
{ "zeroOrMore": ":model(script-supporting)" }
|
|
79
|
+
]
|
|
80
|
+
}]
|
|
81
|
+
}]
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Cross-Package Relationships
|
|
85
|
+
|
|
86
|
+
The content model definitions in these JSON files are part of a larger ecosystem:
|
|
87
|
+
|
|
88
|
+
- **Schema validation** -- `@markuplint/ml-spec` provides `content-models.schema.json` which defines the valid structure of content model patterns (`require`, `optional`, `oneOrMore`, `zeroOrMore`, `choice`, `transparent`). Source JSON files are validated against this schema in tests.
|
|
89
|
+
- **TypeScript types** -- `@markuplint/ml-spec` auto-generates `ContentModel`, `PermittedContentPattern`, and `Category` types from the schema (in `types/permitted-structures.ts`), enabling type-safe access throughout the codebase.
|
|
90
|
+
- **Runtime algorithms** -- `@markuplint/ml-spec` provides `getContentModel()` which evaluates conditional content models at runtime, and `contentModelCategoryToTagNames()` which resolves category names (e.g., `#flow`) to concrete element lists using `def["#contentModels"]` from this package's `spec-common.contents.json`.
|
|
91
|
+
- **Lint rules** -- `@markuplint/rules` uses these definitions in the `permitted-contents` rule (validates element children against content model patterns) and the `no-empty-palpable-content` rule (uses `#palpable` category data to detect empty palpable elements).
|
|
92
|
+
|
|
93
|
+
## Content Model Patterns
|
|
94
|
+
|
|
95
|
+
Each pattern uses exactly one key to describe cardinality or composition.
|
|
96
|
+
|
|
97
|
+
### Cardinality Patterns
|
|
98
|
+
|
|
99
|
+
| Pattern | Meaning |
|
|
100
|
+
| -------------------------------- | ---------------------------- |
|
|
101
|
+
| `{ "require": "<selector>" }` | Exactly one required element |
|
|
102
|
+
| `{ "optional": "<selector>" }` | Zero or one element |
|
|
103
|
+
| `{ "oneOrMore": "<selector>" }` | One or more elements |
|
|
104
|
+
| `{ "zeroOrMore": "<selector>" }` | Zero or more elements |
|
|
105
|
+
|
|
106
|
+
The `oneOrMore` and `zeroOrMore` patterns also accept an array of nested patterns to
|
|
107
|
+
describe a sequence (see the `<div>` conditional example above).
|
|
108
|
+
|
|
109
|
+
### Composition Patterns
|
|
110
|
+
|
|
111
|
+
| Pattern | Meaning |
|
|
112
|
+
| --------------------------------- | -------------------------------------------------------------- |
|
|
113
|
+
| `{ "choice": [...] }` | One of the given options (each option is an array of patterns) |
|
|
114
|
+
| `{ "transparent": "<selector>" }` | Transparent content model with an exclusion selector |
|
|
115
|
+
|
|
116
|
+
The `choice` pattern contains an array of arrays. The `transparent` pattern means the
|
|
117
|
+
element inherits its parent's content model, excluding elements matching the selector.
|
|
118
|
+
|
|
119
|
+
### Selector Syntax
|
|
120
|
+
|
|
121
|
+
| Selector | Description |
|
|
122
|
+
| -------------------------------------- | --------------------------- |
|
|
123
|
+
| `"dt"`, `"li"`, `"div"` | Tag names |
|
|
124
|
+
| `":model(flow)"`, `":model(phrasing)"` | Content category references |
|
|
125
|
+
| `":not(:model(interactive), a)"` | Negation pseudo-class |
|
|
126
|
+
| `":has(:model(interactive))"` | Has pseudo-class |
|
|
127
|
+
| `"#text"` | Text nodes |
|
|
128
|
+
| `"#custom"` | Custom elements |
|
|
129
|
+
| `"svg\|a"`, `"svg\|circle"` | SVG namespace elements |
|
|
130
|
+
| `"link[itemprop]"` | Attribute selectors |
|
|
131
|
+
|
|
132
|
+
## Global Attributes
|
|
133
|
+
|
|
134
|
+
The `globalAttrs` object maps category names (prefixed with `#`) to inclusion rules:
|
|
135
|
+
|
|
136
|
+
| Value | Meaning |
|
|
137
|
+
| ---------- | ---------------------------------------------------- |
|
|
138
|
+
| `true` | Include all attributes from the category |
|
|
139
|
+
| `false` | Exclude the category entirely |
|
|
140
|
+
| `string[]` | Include only the listed attributes from the category |
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
"globalAttrs": {
|
|
144
|
+
"#HTMLGlobalAttrs": true,
|
|
145
|
+
"#GlobalEventAttrs": true,
|
|
146
|
+
"#ARIAAttrs": true,
|
|
147
|
+
"#HTMLLinkAndFetchingAttrs": ["href", "target", "download", "ping", "rel"]
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Available Categories (19)
|
|
152
|
+
|
|
153
|
+
| Category | Description |
|
|
154
|
+
| ----------------------------------- | ------------------------------------------------------------------- |
|
|
155
|
+
| `#HTMLGlobalAttrs` | Standard HTML global attributes (accesskey, class, id, style, etc.) |
|
|
156
|
+
| `#GlobalEventAttrs` | Event handler attributes (onclick, onload, onfocus, etc.) |
|
|
157
|
+
| `#ARIAAttrs` | ARIA attributes (aria-\*, role) |
|
|
158
|
+
| `#HTMLLinkAndFetchingAttrs` | Link and fetch attributes (href, target, download, etc.) |
|
|
159
|
+
| `#HTMLEmbededAndMediaContentAttrs` | Embedded content attributes (src, height, width, etc.) |
|
|
160
|
+
| `#HTMLFormControlElementAttrs` | Form control attributes (autocomplete, disabled, name, etc.) |
|
|
161
|
+
| `#HTMLTableCellElementAttrs` | Table cell attributes (colspan, rowspan, headers, etc.) |
|
|
162
|
+
| `#SVGAnimationAdditionAttrs` | SVG animation addition attributes |
|
|
163
|
+
| `#SVGAnimationAttributeTargetAttrs` | SVG animation attribute target attributes |
|
|
164
|
+
| `#SVGAnimationEventAttrs` | SVG animation event attributes |
|
|
165
|
+
| `#SVGAnimationTargetElementAttrs` | SVG animation target element attributes |
|
|
166
|
+
| `#SVGAnimationTimingAttrs` | SVG animation timing attributes |
|
|
167
|
+
| `#SVGAnimationValueAttrs` | SVG animation value attributes |
|
|
168
|
+
| `#SVGConditionalProcessingAttrs` | SVG conditional processing attributes |
|
|
169
|
+
| `#SVGCoreAttrs` | SVG core attributes (id, tabindex, lang, class, style, etc.) |
|
|
170
|
+
| `#SVGFilterPrimitiveAttrs` | SVG filter primitive attributes |
|
|
171
|
+
| `#SVGPresentationAttrs` | SVG presentation attributes (fill, stroke, transform, etc.) |
|
|
172
|
+
| `#SVGTransferFunctionAttrs` | SVG transfer function attributes |
|
|
173
|
+
| `#XLinkAttrs` | XLink attributes (deprecated) |
|
|
174
|
+
|
|
175
|
+
## Element-Specific Attributes
|
|
176
|
+
|
|
177
|
+
The `attributes` object maps attribute names to definitions. Each definition may contain:
|
|
178
|
+
|
|
179
|
+
| Field | Type | Description |
|
|
180
|
+
| -------------- | -------------------- | ----------------------------------------------- |
|
|
181
|
+
| `type` | various | Attribute value type (see below) |
|
|
182
|
+
| `condition` | `string \| string[]` | CSS selector(s) for when the attribute is valid |
|
|
183
|
+
| `required` | `boolean` | Whether the attribute is required |
|
|
184
|
+
| `defaultValue` | `string` | Default value |
|
|
185
|
+
| `description` | `string` | Human-readable description |
|
|
186
|
+
| `animatable` | `boolean` | Whether the attribute is animatable (SVG) |
|
|
187
|
+
| `deprecated` | `boolean` | Deprecated status flag (see below) |
|
|
188
|
+
| `obsolete` | `boolean` | Obsolete status flag (see below) |
|
|
189
|
+
| `experimental` | `boolean` | Experimental status flag (see below) |
|
|
190
|
+
| `nonStandard` | `boolean` | Non-standard status flag (see below) |
|
|
191
|
+
|
|
192
|
+
### Status Flags
|
|
193
|
+
|
|
194
|
+
These boolean flags indicate the standardization status of an attribute:
|
|
195
|
+
|
|
196
|
+
| Flag | Meaning |
|
|
197
|
+
| -------------- | ------------------------------------------------------------------------------------------------------------- |
|
|
198
|
+
| `experimental` | Part of an emerging specification that is not yet stable. Browsers may have partial or prefixed support. |
|
|
199
|
+
| `deprecated` | Officially discouraged by the specification. Still recognized by browsers but should not be used in new code. |
|
|
200
|
+
| `obsolete` | Removed from the specification entirely. May not be recognized by modern browsers at all. |
|
|
201
|
+
| `nonStandard` | Not part of any W3C or WHATWG specification. Vendor-specific or proprietary. |
|
|
202
|
+
|
|
203
|
+
**`deprecated` vs `obsolete`:** `deprecated` means the spec still defines the attribute
|
|
204
|
+
but discourages its use (e.g., `<table border>`). `obsolete` means the attribute has been
|
|
205
|
+
removed from the specification altogether (e.g., legacy presentational attributes on
|
|
206
|
+
elements that have been fully obsoleted). In practice, `deprecated` attributes usually
|
|
207
|
+
still work in browsers, while `obsolete` attributes may not.
|
|
208
|
+
|
|
209
|
+
**Flag precedence (spec > MDN):** When a flag is set in the manual spec file
|
|
210
|
+
(`src/spec.*.json`), it takes precedence over the MDN-scraped value. This allows you to
|
|
211
|
+
correct cases where MDN data is inaccurate or lagging behind the specification. Flags
|
|
212
|
+
from MDN are used only when the manual spec does not define the attribute or does not
|
|
213
|
+
set that particular flag.
|
|
214
|
+
|
|
215
|
+
**When to set flags manually:**
|
|
216
|
+
|
|
217
|
+
- MDN flags an attribute as `experimental` but the spec has stabilized it -- set
|
|
218
|
+
`"experimental": false` (or omit it) in the spec file to override
|
|
219
|
+
- An attribute is deprecated in the spec but MDN has not yet updated -- set
|
|
220
|
+
`"deprecated": true` in the spec file
|
|
221
|
+
- A vendor-specific attribute needs to be marked -- set `"nonStandard": true`
|
|
222
|
+
|
|
223
|
+
### Attribute Value Types
|
|
224
|
+
|
|
225
|
+
**Simple string types:**
|
|
226
|
+
|
|
227
|
+
`"String"`, `"URL"`, `"Boolean"`, `"DOMID"`, `"Any"`, `"Number"`, `"Pattern"`,
|
|
228
|
+
`"OneLineAny"`, `"CustomElementName"`, `"DateTime"`
|
|
229
|
+
|
|
230
|
+
**Enumerated type:**
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"enum": ["hidden", "text", "search"],
|
|
235
|
+
"invalidValueDefault": "text",
|
|
236
|
+
"missingValueDefault": "text",
|
|
237
|
+
"caseInsensitive": true,
|
|
238
|
+
"disallowToSurroundBySpaces": true,
|
|
239
|
+
"sameStates": { "none": ["off"] }
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| Field | Description |
|
|
244
|
+
| ---------------------------- | ------------------------------------------- |
|
|
245
|
+
| `enum` | Array of allowed string values |
|
|
246
|
+
| `invalidValueDefault` | Default state when the value is invalid |
|
|
247
|
+
| `missingValueDefault` | Default state when the attribute is missing |
|
|
248
|
+
| `caseInsensitive` | Whether matching is case-insensitive |
|
|
249
|
+
| `disallowToSurroundBySpaces` | Whether surrounding spaces are disallowed |
|
|
250
|
+
| `sameStates` | Maps canonical values to their aliases |
|
|
251
|
+
|
|
252
|
+
**Token list type:**
|
|
253
|
+
|
|
254
|
+
```json
|
|
255
|
+
{ "token": "Accept", "separator": "comma", "unique": true, "caseInsensitive": true }
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
| Field | Description |
|
|
259
|
+
| ----------------- | ------------------------------------------------ |
|
|
260
|
+
| `token` | Token type name |
|
|
261
|
+
| `separator` | `"space"` or `"comma"` |
|
|
262
|
+
| `unique` | Whether tokens must be unique |
|
|
263
|
+
| `caseInsensitive` | Whether matching is case-insensitive |
|
|
264
|
+
| `ordered` | Whether order matters |
|
|
265
|
+
| `number` | Cardinality: `"zeroOrMore"`, `"oneOrMore"`, etc. |
|
|
266
|
+
|
|
267
|
+
**Number constraint type:**
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{ "type": "integer", "gt": 0 }
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Fields: `type` (`"integer"` or `"float"`), `gt`, `gte`, `lt`, `lte` for bounds.
|
|
274
|
+
|
|
275
|
+
**Union type (array):** Multiple valid types -- `["DateTime", "Number"]` or
|
|
276
|
+
`["<svg-length>", "<percentage>"]`.
|
|
277
|
+
|
|
278
|
+
**CSS/SVG value types:** Angle-bracket strings like `"<text-coordinate>"`,
|
|
279
|
+
`"<svg-length>"`, `"<percentage>"`, `"<list-of-numbers>"`, `"<number>"`.
|
|
280
|
+
|
|
281
|
+
### Conditional Attributes
|
|
282
|
+
|
|
283
|
+
The `condition` field restricts an attribute to specific element states. It accepts a
|
|
284
|
+
single CSS selector string or an array. The `i` flag enables case-insensitive matching:
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
"accept": { "type": { "token": "Accept", "separator": "comma" }, "condition": "[type='file' i]" },
|
|
288
|
+
"checked": { "type": "Boolean", "condition": ["[type='checkbox' i]", "[type='radio' i]"] }
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## ARIA Integration
|
|
292
|
+
|
|
293
|
+
The `aria` object defines ARIA role and property integration.
|
|
294
|
+
|
|
295
|
+
### Top-Level ARIA Fields
|
|
296
|
+
|
|
297
|
+
| Field | Type | Description |
|
|
298
|
+
| ------------------ | ------------------------------------- | -------------------------------------- |
|
|
299
|
+
| `implicitRole` | `string \| false` | Default ARIA role, or `false` for none |
|
|
300
|
+
| `permittedRoles` | `true \| false \| string[] \| object` | Allowed explicit roles |
|
|
301
|
+
| `namingProhibited` | `boolean` | Whether accessible name is prohibited |
|
|
302
|
+
| `properties` | `object \| false` | ARIA property constraints |
|
|
303
|
+
| `conditions` | `object` | Context-dependent ARIA overrides |
|
|
304
|
+
|
|
305
|
+
### Permitted Roles
|
|
306
|
+
|
|
307
|
+
- `true` -- Any role is permitted
|
|
308
|
+
- `false` -- No explicit roles permitted
|
|
309
|
+
- `string[]` -- Specific permitted role names
|
|
310
|
+
- Object with AAM references (SVG): `{ "core-aam": true, "graphics-aam": true }`
|
|
311
|
+
|
|
312
|
+
Role entries can also be objects: `{ "name": "directory", "deprecated": true }`.
|
|
313
|
+
|
|
314
|
+
### ARIA Properties
|
|
315
|
+
|
|
316
|
+
| Field | Type | Description |
|
|
317
|
+
| --------- | ------------------- | -------------------------------- |
|
|
318
|
+
| `global` | `boolean` | Include global ARIA properties |
|
|
319
|
+
| `role` | `boolean \| string` | Include role-specific properties |
|
|
320
|
+
| `without` | `array` | Property restriction rules |
|
|
321
|
+
|
|
322
|
+
When `properties` is `false`, no ARIA properties are allowed (e.g., `input[type=hidden]`).
|
|
323
|
+
|
|
324
|
+
### Property Restrictions (`without`)
|
|
325
|
+
|
|
326
|
+
| Field | Type | Description |
|
|
327
|
+
| ------- | -------- | ---------------------------------------------------- | ------------------------------------ |
|
|
328
|
+
| `type` | `string` | `"must-not"`, `"should-not"`, or `"not-recommended"` |
|
|
329
|
+
| `name` | `string` | ARIA property name (e.g., `"aria-checked"`) |
|
|
330
|
+
| `value` | `string` | Optional: restrict only for this specific value |
|
|
331
|
+
| `alt` | `object` | Optional: `{ "method": "set-attr" | "remove-attr", "target": "<attr>" }` |
|
|
332
|
+
|
|
333
|
+
### Conditional ARIA (`conditions`)
|
|
334
|
+
|
|
335
|
+
Maps CSS selectors to ARIA overrides. Condition keys use the same CSS selector syntax:
|
|
336
|
+
|
|
337
|
+
- `":not([href])"` -- element without `href`
|
|
338
|
+
- `"[type='button' i]"` -- input with `type="button"`
|
|
339
|
+
- `"dl > div"` -- div as direct child of dl
|
|
340
|
+
- `"[type='checkbox' i][aria-pressed]"` -- compound selectors
|
|
341
|
+
|
|
342
|
+
### Version-Specific ARIA Overrides
|
|
343
|
+
|
|
344
|
+
Use version keys (`"1.1"`, `"1.2"`) as sibling properties to override ARIA for specific
|
|
345
|
+
spec versions. Version overrides can contain their own `conditions` object:
|
|
346
|
+
|
|
347
|
+
```json
|
|
348
|
+
"aria": {
|
|
349
|
+
"implicitRole": "paragraph",
|
|
350
|
+
"permittedRoles": true,
|
|
351
|
+
"1.1": { "implicitRole": false }
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Common Files
|
|
356
|
+
|
|
357
|
+
### spec-common.attributes.json
|
|
358
|
+
|
|
359
|
+
Defines the 19 global attribute categories. Each category maps attribute names to
|
|
360
|
+
definitions using the same format described in the attributes section.
|
|
361
|
+
|
|
362
|
+
### spec-common.contents.json
|
|
363
|
+
|
|
364
|
+
Defines content model category macros referenced via `:model()`. Structure:
|
|
365
|
+
|
|
366
|
+
```json
|
|
367
|
+
{ "models": { "#metadata": ["base", "link", ...], "#flow": ["a", "abbr", ...], ... } }
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Content Model Categories
|
|
371
|
+
|
|
372
|
+
**HTML categories (10):**
|
|
373
|
+
|
|
374
|
+
| Category | Description |
|
|
375
|
+
| -------------------- | ---------------------------------------------------------- |
|
|
376
|
+
| `#metadata` | Document metadata elements (base, link, meta, etc.) |
|
|
377
|
+
| `#flow` | Most body-level elements |
|
|
378
|
+
| `#sectioning` | Section elements (article, aside, nav, section) |
|
|
379
|
+
| `#heading` | Heading elements (h1-h6, hgroup) |
|
|
380
|
+
| `#phrasing` | Inline-level elements |
|
|
381
|
+
| `#embedded` | Embedded content (audio, canvas, embed, iframe, img, etc.) |
|
|
382
|
+
| `#interactive` | Interactive elements (a[href], button, details, etc.) |
|
|
383
|
+
| `#palpable` | Elements that render visible content |
|
|
384
|
+
| `#script-supporting` | Script-supporting elements (script, template) |
|
|
385
|
+
|
|
386
|
+
**SVG categories (19):**
|
|
387
|
+
|
|
388
|
+
| Category | Description |
|
|
389
|
+
| -------------------------- | ----------------------------------------------------------------- |
|
|
390
|
+
| `#SVGAnimation` | Animation elements (animate, animateMotion, set, etc.) |
|
|
391
|
+
| `#SVGBasicShapes` | Basic shape elements (circle, ellipse, line, polygon, etc.) |
|
|
392
|
+
| `#SVGContainer` | Container elements (a, defs, g, marker, svg, symbol, etc.) |
|
|
393
|
+
| `#SVGDescriptive` | Descriptive elements (desc, metadata, title) |
|
|
394
|
+
| `#SVGFilterPrimitive` | Filter primitive elements (feBlend, feColorMatrix, etc.) |
|
|
395
|
+
| `#SVGFont` | Font elements (font, font-face, glyph, etc.) |
|
|
396
|
+
| `#SVGGradient` | Gradient elements (linearGradient, radialGradient, stop) |
|
|
397
|
+
| `#SVGGraphics` | Graphics elements (circle, image, path, text, use, etc.) |
|
|
398
|
+
| `#SVGGraphicsReferencing` | Graphics referencing elements (use) |
|
|
399
|
+
| `#SVGLightSource` | Light source elements (feDistantLight, fePointLight, feSpotLight) |
|
|
400
|
+
| `#SVGNeverRendered` | Never-rendered elements (clipPath, defs, metadata, etc.) |
|
|
401
|
+
| `#SVGPaintServer` | Paint server elements (linearGradient, pattern, etc.) |
|
|
402
|
+
| `#SVGRenderable` | Renderable elements (a, circle, g, svg, text, etc.) |
|
|
403
|
+
| `#SVGShape` | Shape elements (circle, ellipse, line, path, polygon, etc.) |
|
|
404
|
+
| `#SVGStructural` | Structural elements (defs, g, svg, symbol, use) |
|
|
405
|
+
| `#SVGStructurallyExternal` | Structurally external elements (currently empty) |
|
|
406
|
+
| `#SVGTextContent` | Text content elements (text, textPath, tspan, etc.) |
|
|
407
|
+
| `#SVGTextContentChild` | Text content child elements (textPath, tspan, etc.) |
|
|
408
|
+
|
|
409
|
+
## Full Examples
|
|
410
|
+
|
|
411
|
+
### Simple HTML Element -- `<p>`
|
|
412
|
+
|
|
413
|
+
```json
|
|
414
|
+
// https://html.spec.whatwg.org/multipage/grouping-content.html#the-p-element
|
|
415
|
+
{
|
|
416
|
+
"contentModel": {
|
|
417
|
+
"contents": [{ "oneOrMore": ":model(phrasing)" }]
|
|
418
|
+
},
|
|
419
|
+
"globalAttrs": {
|
|
420
|
+
"#HTMLGlobalAttrs": true,
|
|
421
|
+
"#GlobalEventAttrs": true,
|
|
422
|
+
"#ARIAAttrs": true
|
|
423
|
+
},
|
|
424
|
+
"attributes": {},
|
|
425
|
+
"aria": {
|
|
426
|
+
"implicitRole": "paragraph",
|
|
427
|
+
"permittedRoles": true,
|
|
428
|
+
"namingProhibited": true,
|
|
429
|
+
"1.1": { "implicitRole": false }
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### Complex HTML Element -- `<a>`
|
|
435
|
+
|
|
436
|
+
```json
|
|
437
|
+
// https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element
|
|
438
|
+
{
|
|
439
|
+
"contentModel": {
|
|
440
|
+
"contents": [
|
|
441
|
+
{ "transparent": ":not(:model(interactive), a, [tabindex], :has(:model(interactive), a, [tabindex]))" }
|
|
442
|
+
]
|
|
443
|
+
},
|
|
444
|
+
"globalAttrs": {
|
|
445
|
+
"#HTMLGlobalAttrs": true,
|
|
446
|
+
"#GlobalEventAttrs": true,
|
|
447
|
+
"#ARIAAttrs": true,
|
|
448
|
+
"#HTMLLinkAndFetchingAttrs": ["href", "target", "download", "ping", "rel", "hreflang", "type", "referrerpolicy"]
|
|
449
|
+
},
|
|
450
|
+
"attributes": {},
|
|
451
|
+
"aria": {
|
|
452
|
+
"implicitRole": "link",
|
|
453
|
+
"permittedRoles": ["button", "checkbox", "menuitem", "option", "radio", "switch", "tab", "treeitem"],
|
|
454
|
+
"properties": {
|
|
455
|
+
"global": true,
|
|
456
|
+
"role": true,
|
|
457
|
+
"without": [
|
|
458
|
+
{
|
|
459
|
+
"type": "not-recommended",
|
|
460
|
+
"name": "aria-disabled",
|
|
461
|
+
"value": "true",
|
|
462
|
+
"alt": { "method": "remove-attr", "target": "href" }
|
|
463
|
+
}
|
|
464
|
+
]
|
|
465
|
+
},
|
|
466
|
+
"conditions": {
|
|
467
|
+
":not([href])": { "implicitRole": "generic", "permittedRoles": true, "namingProhibited": true }
|
|
468
|
+
},
|
|
469
|
+
"1.1": { "conditions": { ":not([href])": { "implicitRole": false } } }
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### SVG Element -- `svg:text`
|
|
475
|
+
|
|
476
|
+
```json
|
|
477
|
+
// https://svgwg.org/svg2-draft/text.html#TextElement
|
|
478
|
+
{
|
|
479
|
+
"contentModel": {
|
|
480
|
+
"contents": [
|
|
481
|
+
{
|
|
482
|
+
"zeroOrMore": [
|
|
483
|
+
"#text",
|
|
484
|
+
":model(SVGAnimation)",
|
|
485
|
+
":model(SVGDescriptive)",
|
|
486
|
+
":model(SVGPaintServer)",
|
|
487
|
+
":model(SVGTextContentChild)",
|
|
488
|
+
"svg|a",
|
|
489
|
+
"svg|clipPath",
|
|
490
|
+
"svg|marker",
|
|
491
|
+
"svg|mask",
|
|
492
|
+
"svg|script",
|
|
493
|
+
"svg|style"
|
|
494
|
+
]
|
|
495
|
+
}
|
|
496
|
+
]
|
|
497
|
+
},
|
|
498
|
+
"globalAttrs": {
|
|
499
|
+
"#HTMLGlobalAttrs": true,
|
|
500
|
+
"#GlobalEventAttrs": true,
|
|
501
|
+
"#ARIAAttrs": true,
|
|
502
|
+
"#SVGConditionalProcessingAttrs": ["requiredExtensions", "systemLanguage"],
|
|
503
|
+
"#SVGCoreAttrs": ["id", "tabindex", "autofocus", "lang", "xml:space", "class", "style"],
|
|
504
|
+
"#SVGPresentationAttrs": ["alignment-baseline", "fill", "font-size", "stroke", "transform"]
|
|
505
|
+
},
|
|
506
|
+
"attributes": {
|
|
507
|
+
"x": { "type": "<text-coordinate>", "defaultValue": "0", "animatable": true },
|
|
508
|
+
"y": { "type": "<text-coordinate>", "defaultValue": "0", "animatable": true },
|
|
509
|
+
"textLength": { "type": ["<svg-length>", "<percentage>"], "animatable": true },
|
|
510
|
+
"lengthAdjust": {
|
|
511
|
+
"type": { "enum": ["spacing", "spacingAndGlyphs"] },
|
|
512
|
+
"defaultValue": "spacing",
|
|
513
|
+
"animatable": true
|
|
514
|
+
}
|
|
515
|
+
},
|
|
516
|
+
"aria": {
|
|
517
|
+
"implicitRole": "group",
|
|
518
|
+
"permittedRoles": { "core-aam": true, "graphics-aam": true }
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
```
|