\n → Abuses id attribute\n✓ data-category=\"electronics\"\n → Semantic & maintainable"
},
"validations": [
{
"type": "element_count",
"value": { "selector": "article[data-category]", "min": 2 },
"message": "Create at least 2 articles with data-category attributes"
},
{
"type": "element_count",
"value": { "selector": "article[data-price]", "min": 2 },
"message": "Add data-price attribute to your articles"
},
{
"type": "element_count",
"value": { "selector": "article h2", "min": 2 },
"message": "Add an
<h2> inside each article"
}
]
},
{
"id": "data-attributes-css",
"title": "Styling with Data Attributes",
"description": "CSS can select elements by their data attributes using
[data-*] selectors. You can even match specific values!
The preview CSS uses
[data-status='active'] to style active items differently.",
"task": "Create a task list with 3
<li> items. Give each a
data-status attribute:
1. One with
data-status=\"completed\"2. One with
data-status=\"active\"3. One with
data-status=\"pending\"",
"previewHTML": "",
"previewBaseCSS": "body { font-family: system-ui; padding: 20px; } ul { list-style: none; padding: 0; } li { padding: 15px; margin: 8px 0; border-radius: 8px; background: #f5f5f5; } li[data-status='completed'] { background: #c8e6c9; text-decoration: line-through; color: #388e3c; } li[data-status='active'] { background: #fff3e0; border-left: 4px solid #ff9800; font-weight: 600; } li[data-status='pending'] { background: #e3f2fd; color: #1976d2; }",
"sandboxCSS": "",
"initialCode": "
",
"solution": "
\n - Buy groceries
\n - Finish homework
\n - Call mom
\n
",
"previewContainer": "preview-area",
"concept": {
"explanation": "CSS attribute selectors enable state-based styling without adding/removing classes via JavaScript—you just change the attribute value and CSS reactivity handles the rest. The selector [data-status='active'] has the same specificity as a class (0,0,1,0), making it equally powerful but more semantic for data-driven states. This pattern shines in component libraries and SPAs where state changes frequently: updating one attribute triggers CSS transitions and visual changes automatically. Unlike classes that describe presentation (\"button-blue\"), data attributes describe meaning (\"status=active\"), and CSS translates meaning to presentation, keeping your HTML semantic and your styling decoupled from implementation details.",
"diagram": "CSS Attribute Selectors\n\nAttribute Selector Syntax:\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n[data-status] → Has attribute\n[data-status=\"active\"] → Exact match\n[data-status^=\"act\"] → Starts with\n[data-status$=\"ed\"] → Ends with\n[data-status*=\"iv\"] → Contains\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nState-Based Styling:\n\n
\n ↓ CSS applies\nli[data-status=\"pending\"] {\n background: lightblue;\n}\n\nJS changes state:\nel.dataset.status = \"active\"\n ↓ CSS automatically updates\nli[data-status=\"active\"] {\n background: orange;\n}\n\nvs Class Approach:\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\ndata-status=\"active\"\n✓ Semantic (describes state)\n✓ One attribute to update\n✓ Clear data meaning\n\nclass=\"task active pending\"\n✗ Presentational\n✗ Multiple classes to manage\n✗ Unclear which is data\n\nSpecificity:\n[data-status=\"active\"] = .active\nBoth have 0,0,1,0 specificity"
},
"validations": [
{
"type": "element_exists",
"value": "li[data-status='completed']",
"message": "Add an item with data-status=\"completed\""
},
{
"type": "element_exists",
"value": "li[data-status='active']",
"message": "Add an item with data-status=\"active\""
},
{
"type": "element_exists",
"value": "li[data-status='pending']",
"message": "Add an item with data-status=\"pending\""
}
]
}
]
}