@schalkneethling/toolkit 0.1.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.
@@ -0,0 +1,111 @@
1
+ # Element Decision Trees
2
+
3
+ Quick decision frameworks for selecting the right HTML element.
4
+
5
+ ## Is It a List?
6
+
7
+ ```
8
+ Does knowing the count help the user?
9
+ ├─ Yes → Are items sequential/ranked?
10
+ │ ├─ Yes → <ol>
11
+ │ └─ No → <ul>
12
+ ├─ No → Are these term-description pairs?
13
+ │ ├─ Yes → <dl>
14
+ │ └─ No → Consider plain elements with appropriate structure
15
+ └─ Is it a toolbar of commands?
16
+ └─ Yes → <menu>
17
+ ```
18
+
19
+ ## Is It a Table?
20
+
21
+ ```
22
+ Does data have meaningful rows AND columns?
23
+ ├─ No → Not a table
24
+ │ ├─ One dimension only → List or plain elements
25
+ │ ├─ Key-value pairs → <dl>
26
+ │ └─ Hierarchical → Nested lists or other structure
27
+ └─ Yes → Does each row have the same columns?
28
+ ├─ No → Reconsider data structure
29
+ └─ Yes → Use <table> with full semantics
30
+ ```
31
+
32
+ ## Button or Link?
33
+
34
+ ```
35
+ Does this navigate to a new URL?
36
+ ├─ Yes → <a href="...">
37
+ └─ No → Does an action occur?
38
+ ├─ Yes → Would a URL provide useful fallback if JS fails?
39
+ │ ├─ Yes → <a href="..."> with JS enhancement
40
+ │ └─ No → <button>
41
+ └─ No → Reconsider if interaction is needed
42
+ ```
43
+
44
+ ## Section or Div?
45
+
46
+ ```
47
+ Does this content form a thematic grouping?
48
+ ├─ No → <div>
49
+ └─ Yes → Can you provide a meaningful accessible name?
50
+ ├─ Yes → <section aria-labelledby="...">
51
+ └─ No → <div> (section without label ≈ div semantically)
52
+ ```
53
+
54
+ ## Article Candidate?
55
+
56
+ ```
57
+ Would this content make sense standalone?
58
+ ├─ Yes → Could it be syndicated or extracted?
59
+ │ ├─ Yes → <article>
60
+ │ └─ No → Use appropriate container (section, div, etc.)
61
+ └─ No → Use appropriate container (section, div, etc.)
62
+ ```
63
+
64
+ ## Which Landmark?
65
+
66
+ ```
67
+ What is this section's purpose?
68
+ ├─ Site/section header → <header>
69
+ ├─ Site/section footer → <footer>
70
+ ├─ Navigation → <nav> (must be labelled)
71
+ ├─ Primary page content → <main>
72
+ ├─ Search/filter functionality → <search> (wrap ALL related controls, not just the text input)
73
+ ├─ User input → <form> (must be labelled to be a landmark)
74
+ ├─ Tangentially related → <aside>
75
+ ├─ Self-contained content → <article>
76
+ └─ Thematic grouping with label → <section aria-labelledby="...">
77
+ ```
78
+
79
+ ## Form Field Grouping
80
+
81
+ ```
82
+ Do these fields form a logical/thematic group?
83
+ ├─ Yes → Are they form controls (inputs, selects, checkboxes)?
84
+ │ ├─ Yes → <fieldset> with <legend>
85
+ │ └─ No → <section aria-labelledby="...">
86
+ └─ No → Is visual grouping needed?
87
+ ├─ Yes → <div> with appropriate styling
88
+ └─ No → Fields can exist without wrapper
89
+ ```
90
+
91
+ ## Interactive Disclosure
92
+
93
+ ```
94
+ Should content be expandable/collapsible?
95
+ ├─ Yes → Does the disclosed content need ARIA roles (menu, dialog, etc.)?
96
+ │ ├─ Yes → <button> controlling visibility + appropriate ARIA
97
+ │ └─ No → Is it a single content section?
98
+ │ ├─ Yes → <details>/<summary>
99
+ │ └─ No → Consider tab pattern or custom disclosure
100
+ └─ No → Is it a list of definitions?
101
+ └─ Yes → <dl> (not details/summary)
102
+ ```
103
+
104
+ ## Skip Navigation
105
+
106
+ ```
107
+ Does the page have a <nav> or repeated content before <main>?
108
+ └─ Yes → Add <a href="#main-content"> as the first element in <body>
109
+ Does the page have a prominent search bar or long sidebar?
110
+ └─ Yes → Add additional skip links to those targets
111
+ ```
@@ -0,0 +1,275 @@
1
+ # Heading Patterns in Component Systems
2
+
3
+ Strategies for maintaining proper heading hierarchy in component-based architectures.
4
+
5
+ ## The Challenge
6
+
7
+ Component-based development creates a tension:
8
+
9
+ - Components should be reusable across contexts
10
+ - Heading levels depend on surrounding document structure
11
+ - Content authors may not understand heading hierarchy
12
+ - Hardcoded levels break in different contexts
13
+
14
+ ## Pattern 1: Configurable Heading Level
15
+
16
+ Make heading level a prop/parameter with a sensible default.
17
+
18
+ ```jsx
19
+ // React example
20
+ function Card({ title, headingLevel = 3, children }) {
21
+ const Heading = `h${headingLevel}`;
22
+ return (
23
+ <article className="card">
24
+ <Heading>{title}</Heading>
25
+ {children}
26
+ </article>
27
+ );
28
+ }
29
+ ```
30
+
31
+ ```twig
32
+ {# Twig example #}
33
+ {% set heading_tag = heading_level|default(3) %}
34
+ <article class="card">
35
+ <h{{ heading_tag }}>{{ title }}</h{{ heading_tag }}>
36
+ {{ content }}
37
+ </article>
38
+ ```
39
+
40
+ ### When to Use
41
+
42
+ - Generic components used in multiple contexts
43
+ - Components where nesting depth varies
44
+ - CMS-driven content where authors control usage
45
+
46
+ ### Trade-offs
47
+
48
+ - Moves responsibility to component consumer
49
+ - Authors may not choose correctly
50
+ - Sensible default reduces but doesn't eliminate risk
51
+
52
+ ## Pattern 2: Context-Aware Defaults
53
+
54
+ Set defaults based on known component relationships.
55
+
56
+ ```jsx
57
+ // Section always starts a new heading context
58
+ function Section({ title, children }) {
59
+ return (
60
+ <section aria-labelledby="section-title">
61
+ <h2 id="section-title">{title}</h2>
62
+ {children}
63
+ </section>
64
+ );
65
+ }
66
+
67
+ // Cards within sections default to h3
68
+ function CardList({ cards }) {
69
+ return (
70
+ <ul className="card-list">
71
+ {cards.map((card) => (
72
+ <li key={card.id}>
73
+ <Card title={card.title} headingLevel={3} />
74
+ </li>
75
+ ))}
76
+ </ul>
77
+ );
78
+ }
79
+ ```
80
+
81
+ ### When to Use
82
+
83
+ - Known parent-child component relationships
84
+ - Design systems with predictable nesting patterns
85
+ - When you control both container and child components
86
+
87
+ ### Trade-offs
88
+
89
+ - Less flexible
90
+ - Breaks if components are used outside expected context
91
+ - Requires documentation of expected usage
92
+
93
+ ## Pattern 3: Heading Component Abstraction
94
+
95
+ Create a heading component that handles both semantic and visual concerns.
96
+
97
+ ```jsx
98
+ function Heading({ level, visualLevel = level, children, className = "" }) {
99
+ const Tag = `h${level}`;
100
+ const visualClass = `u-heading-${visualLevel}`;
101
+
102
+ return <Tag className={`${visualClass} ${className}`}>{children}</Tag>;
103
+ }
104
+
105
+ // Usage: semantic h3, visual appearance of h2
106
+ <Heading level={3} visualLevel={2}>
107
+ Section Title
108
+ </Heading>;
109
+ ```
110
+
111
+ ### When to Use
112
+
113
+ - Design requires visual hierarchy different from semantic
114
+ - Large headings needed at deep nesting levels
115
+ - Consistent visual treatment across varying semantic levels
116
+
117
+ ### Benefits
118
+
119
+ - Separates concerns clearly
120
+ - Documents the distinction explicitly
121
+ - Enables correct semantics without design compromise
122
+
123
+ ## Pattern 4: Inherited Configuration
124
+
125
+ Generic components inherit heading config when specialised.
126
+
127
+ ```jsx
128
+ // Generic card
129
+ function Card({ title, headingLevel = 3, headingClass, children }) {
130
+ const Heading = `h${headingLevel}`;
131
+ return (
132
+ <article className="card">
133
+ <Heading className={headingClass}>{title}</Heading>
134
+ {children}
135
+ </article>
136
+ );
137
+ }
138
+
139
+ // Specialised product card - knows its context
140
+ function ProductCard({ product, headingLevel = 3 }) {
141
+ return (
142
+ <Card
143
+ title={product.name}
144
+ headingLevel={headingLevel}
145
+ headingClass="product-card__title"
146
+ >
147
+ <p className="product-card__price">{product.price}</p>
148
+ <p className="product-card__description">{product.description}</p>
149
+ </Card>
150
+ );
151
+ }
152
+
153
+ // Page section - sets context for children
154
+ function FeaturedProducts({ products }) {
155
+ return (
156
+ <section aria-labelledby="featured-heading">
157
+ <h2 id="featured-heading">Featured Products</h2>
158
+ <ul className="product-grid">
159
+ {products.map((product) => (
160
+ <li key={product.id}>
161
+ <ProductCard product={product} headingLevel={3} />
162
+ </li>
163
+ ))}
164
+ </ul>
165
+ </section>
166
+ );
167
+ }
168
+ ```
169
+
170
+ ### When to Use
171
+
172
+ - Design systems with component inheritance
173
+ - When generic components are always wrapped by specific ones
174
+ - Clear ownership of heading level decision
175
+
176
+ ## Visual-Only Headings
177
+
178
+ When text should look like a heading but not affect document outline:
179
+
180
+ ```html
181
+ <!-- Looks like a heading, but isn't one semantically -->
182
+ <p class="u-heading-xl">Sale ends tomorrow!</p>
183
+
184
+ <!-- Compare to actual heading -->
185
+ <h2 class="u-heading-xl">Product Categories</h2>
186
+ ```
187
+
188
+ ### When to Use
189
+
190
+ - Promotional text that looks prominent but isn't structural
191
+ - Decorative typography
192
+ - Labels that don't introduce content sections
193
+
194
+ ### CSS Utility Classes
195
+
196
+ ```css
197
+ /* Size-based utilities separate from semantic level */
198
+ .u-heading-xs {
199
+ font-size: var(--font-size-xs);
200
+ }
201
+ .u-heading-s {
202
+ font-size: var(--font-size-s);
203
+ }
204
+ .u-heading-m {
205
+ font-size: var(--font-size-m);
206
+ }
207
+ .u-heading-l {
208
+ font-size: var(--font-size-l);
209
+ }
210
+ .u-heading-xl {
211
+ font-size: var(--font-size-xl);
212
+ }
213
+
214
+ /* All share heading-like properties */
215
+ .u-heading-xs,
216
+ .u-heading-s,
217
+ .u-heading-m,
218
+ .u-heading-l,
219
+ .u-heading-xl {
220
+ font-weight: var(--font-weight-bold);
221
+ line-height: var(--line-height-tight);
222
+ }
223
+ ```
224
+
225
+ ## Checklist for Component Headings
226
+
227
+ When building a component with a heading:
228
+
229
+ - [ ] Is the heading level configurable?
230
+ - [ ] Is there a sensible default?
231
+ - [ ] Is the default documented?
232
+ - [ ] Can visual appearance be controlled independently?
233
+ - [ ] Does the component work at all reasonable heading levels?
234
+ - [ ] Is the expected context documented?
235
+
236
+ ## Common Mistakes
237
+
238
+ ### Hardcoded Levels
239
+
240
+ ```jsx
241
+ // Fragile: breaks when used outside expected context
242
+ function Card({ title }) {
243
+ return (
244
+ <article>
245
+ <h3>{title}</h3> {/* What if this is used at h2 level? */}
246
+ </article>
247
+ );
248
+ }
249
+ ```
250
+
251
+ ### Level Chosen for Appearance
252
+
253
+ ```html
254
+ <!-- Wrong: h4 chosen because it's smaller -->
255
+ <h4 class="card-title">Product Name</h4>
256
+
257
+ <!-- Right: appropriate level with visual override -->
258
+ <h3 class="card-title u-heading-s">Product Name</h3>
259
+ ```
260
+
261
+ ### Missing Defaults
262
+
263
+ ```jsx
264
+ // Dangerous: undefined heading level
265
+ function Card({ title, headingLevel }) {
266
+ const Heading = `h${headingLevel}`; // h undefined if not passed
267
+ return <Heading>{title}</Heading>;
268
+ }
269
+
270
+ // Safe: always has a valid level
271
+ function Card({ title, headingLevel = 3 }) {
272
+ const Heading = `h${headingLevel}`;
273
+ return <Heading>{title}</Heading>;
274
+ }
275
+ ```