Introducing the `context` Attribute: A New Standard for Semantic Web Markup

Modern web development, especially with frameworks like React, often produces HTML that is visually correct but semantically ambiguous. Class and ID names are frequently auto-generated or used solely for styling and JavaScript hooks, making it difficult for both humans and AI to understand the true intent of each element.

<!-- Opaque, meaningless (typical of React or CSS-in-JS) -->
<div id="r1c2a3b4c5" class="css-1a2b3c4"></div>
<div class="sc-xyz123-0 kLJQwA"></div>

<!-- Human-readable, meaningful -->
<div id="faqs-section"></div>
<div class="author-title"></div>

While the latter examples provide context, relying on class or ID names for semantic meaning is not ideal and are often repurposed for styling or dynamic behavior not creating a clear separation of presentation and function. I've been thinking alot about a dedicated context attribute for HTML elements. This attribute encodes the semantic role or intent of an element, separate from its styling or dynamic data.

<!-- class for style/presentation -->
<!-- context for semantic meaning -->
<div class="card-title" context="author-title">Jane Doe</div>

Why Not aria-*, data-*, id, class, or itemscope?

ARIA attributes (like aria-label, aria-role) are designed for accessibility, specifically to help screen readers and assistive technologies interpret web content. They are not intended for general semantic annotation or AI-driven workflows. ARIA's primary audience is accessibility tools, and its vocabulary is specific to accessibility needs.

 <!-- ARIA for screen readers -->
<button aria-label="Close dialog">✕</button>

Microdata and RDFa (e.g. item-scope) are standards for embedding structured data in HTML, usually for search engines and knowledge graphs. They require using pre-defined vocabularies (like schema.org), which can be too rigid or verbose for many real-world content needs. Microdata is best for marking up entities for external consumption, not for subjective, project-specific context.

<div itemscope itemtype="https://schema.org/Person">
  <span itemprop="name">Jane Doe</span>
</div>

Data attributes (e.g. data-*) are meant for dynamic data and JavaScript hooks. While you can add semantic context using a data attribute (e.g., data-context), this is not their primary purpose. Data attributes are meant for storing custom data private to the page or application, often for scripting or state.

<div class="user-card" data-user-id="123" data-state="expanded"></div>

ID attributes are meant to be unique within a page and are primarily used for JavaScript targeting and as URL-friendly hash anchors (e.g., #section-faqs or #what-is-context-attr). While useful for navigation and scripting, they are not intended to convey semantic meaning about the content itself even some meaning can be extacted.

<!-- Link: <a href="#faq-1">Jump to FAQ</a> -->
<h2 id="faq-1">What is context?</h2>

Classes are meant for presentation. While they can become descriptive using BEM (Block Element Modifier) or OOCSS (Object Oriented CSS), their focus should be on the element/component for styling not to communicate semantic intent. When BEM classes try to combine both presentational and semantic intent, they can become unwieldy and ambiguous.

<!-- Style + semantic context, clearly separated -->
<div class="card-header__title"></div>
<!-- Using BEM to combine style and semantic intent (author-title) -->
<div class="card-header__author-title"></div> 

How context Differs

Benefits

Final Note

While context is ideal for clarity and semantics, current tooling and frameworks (including React and some HTML validators) may not fully support custom attributes without the data- prefix. However, for most modern browsers and JavaScript, you can select and manipulate the context attribute directly via the DOM (e.g., document.querySelector('[context="faq-question"]')).

By making this small change in how we develop, we enable immediate, robust HTML-to-JSON extraction, unlocking what I call an HTML-driven API. This means anyone who understands HTML and structured data can create an API or data contract directly from the markup—no need for separate backend schemas or complex integrations. The structure and content of the API payload are derived from the annotated HTML itself, using context attributes to map markup to JSON objects that preserve both presentational and semantic meaning. This approach lets the frontend drive the data model, ensures consistency between UI and data, and empowers rapid prototyping and integration.

Example: Putting It All Together

This flow shows how annotated HTML can be extracted to JSON, processed by a backend or AI, and then used to update the UI—enabling a seamless, dynamic, and intelligent web experience.

Composing HTML

<section class="accordion" context="faq-list">
  <div class="accordion-item" context="faq-item">
    <h2 class="accordion-item__title" context="faq-question" aria-label="FAQ Question" role="button" aria-expanded="false" tabindex="0">What is context?</h2>
    <div class="accordion-item__desc" context="faq-answer" role="region">A semantic marker for intent.</div>
  </div>
</section>

Extracting JSON with JavaScript

const faqList = Array.from(document.querySelectorAll('[context="faq-item"]')).map(item => ({
  "faq-question": item.querySelector('[context="faq-question"]')?.textContent.trim() || '',
  "faq-answer": item.querySelector('[context="faq-answer"]')?.textContent.trim() || ''
}));
const result = { "faq-list": faqList };

Generated JSON (HTML-Driven API) for Backend/AI Automation

// Can stores as JS module or JSON
{
  "faq-list": [
    {
      "faq-question": "What is context?",
      "faq-answer": "A semantic marker for intent."
    }
  ]
}

Dynamic HTML Update from API/JSON

// Select the all faqItems
const faqItems = document.querySelectorAll('[context="faq-item"]');

// Option 1: Backend or local fetch (API)
fetch('/faqs.json').then(res => res.json()).then(data => { /* see below */});

// Option 2: Import as JS module (faqs.js exports the JSON)
import { data } from './faqs.js';

data["faq-list"].forEach((faq, i) => {
  const item = faqItems[i];
  if (item) {
    const q = item.querySelector('[context="faq-question"]');
    const a = item.querySelector('[context="faq-answer"]');
    if (q) q.textContent = faq["faq-question"];
    if (a) a.textContent = faq["faq-answer"];
  }
});

If context were to become a new standard the real challenge is not technical, but social: developer adoption and education. Like Microdata, RDFa, Schema.org, and accessibility rules before it, the value of context will only be realized if teams understand, believe in, and apply it.

Back to top