HTML Guides for span
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The HTML specification defines a specific set of allowed attributes for each element. The <span> element supports global attributes (such as id, class, style, title, etc.) but does not recognize currency as a valid attribute. When you add a non-standard attribute like currency to an element, the W3C validator flags it because it doesn’t conform to the HTML standard.
This pattern often appears in e-commerce sites, financial applications, or internationalization contexts where developers want to associate a currency code (like USD, EUR, or GBP) with a price displayed in a <span>. While browsers will typically ignore unrecognized attributes without breaking the page, using them creates several problems:
- Standards compliance: Invalid HTML can lead to unpredictable behavior across different browsers and future browser versions.
- Maintainability: Other developers (or tools) won’t recognize non-standard attributes, making the codebase harder to understand and maintain.
- Accessibility: Assistive technologies rely on valid, well-structured HTML. Non-standard attributes may be ignored or misinterpreted.
- JavaScript interoperability: The HTMLElement.dataset API is specifically designed to work with data-* attributes, providing a clean and standard way to read custom data from elements.
The fix is straightforward: HTML provides the data-* attribute mechanism specifically for embedding custom data on elements. Any attribute prefixed with data- is valid on any HTML element, and its value is accessible in JavaScript via the element.dataset property.
Examples
❌ Invalid: Non-standard currency attribute
<span currency="USD">49.99</span>
This triggers the validation error because currency is not a recognized attribute for <span>.
✅ Fixed: Using a data-currency attribute
<span data-currency="USD">49.99</span>
The data-currency attribute is valid HTML. In JavaScript, you can access its value like this:
const span = document.querySelector('span');
console.log(span.dataset.currency); // "USD"
✅ Alternative: Using data-* with richer markup
If you need to convey more structured information, you can combine multiple data-* attributes:
<span class="price" data-currency="EUR" data-amount="29.99">€29.99</span>
✅ Alternative: Using microdata or structured markup
For SEO and machine-readable data, consider using established vocabularies like Schema.org:
<span itemscope itemtype="https://schema.org/MonetaryAmount">
<meta itemprop="currency" content="USD">
<span itemprop="value">49.99</span>
</span>
This approach provides semantic meaning that search engines and other consumers can understand, while remaining fully valid HTML.
The HTML specification defines a specific set of global attributes (like class, id, title, style, etc.) that are allowed on all elements, plus element-specific attributes for certain tags. Any attribute that isn’t part of these standard sets and doesn’t follow the data-* custom attribute convention is considered invalid and will trigger a validation error.
This issue is especially common with older integrations of third-party tools like ShareThis, AddThis, or similar social sharing widgets, particularly when embedded through a CMS like Drupal or WordPress. These older implementations relied on proprietary attributes such as displayText, st_url, and st_title directly on <span> or other elements. Modern versions of these tools have since migrated to valid data-* attributes.
Why This Matters
- Standards compliance: Non-standard attributes violate the HTML specification, meaning your markup is technically invalid and may behave unpredictably across browsers.
- Forward compatibility: Browsers could introduce a native displaytext attribute in the future with entirely different behavior, causing conflicts with your code.
- Accessibility: Assistive technologies rely on well-formed HTML. Non-standard attributes can confuse screen readers or other tools that parse the DOM.
- Maintainability: Using the standardized data-* convention makes it immediately clear to other developers that an attribute holds custom data, improving code readability.
How to Fix It
- Identify all non-standard attributes on your elements (e.g., displayText, st_url, st_title).
- Prefix each one with data- to convert it into a valid custom data attribute (e.g., data-displaytext, data-st-url, data-st-title).
- Update any JavaScript that references these attributes. If JavaScript accesses them via element.getAttribute('displayText'), change it to element.getAttribute('data-displaytext') or use the dataset API (element.dataset.displaytext).
- If using a CMS or third-party plugin, update the plugin or module to its latest version, which likely uses valid data-* attributes already.
Note that data-* attribute names should be all lowercase. Even if the original attribute used camelCase like displayText, the corrected version should be data-displaytext.
Examples
Invalid: Non-standard attribute on a <span>
<span class="st_sharethis" displaytext="ShareThis" st_url="https://example.com" st_title="My Page">
Share
</span>
This triggers validation errors for displaytext, st_url, and st_title because none of these are valid HTML attributes.
Valid: Using data-* attributes
<span class="st_sharethis" data-displaytext="ShareThis" data-st-url="https://example.com" data-st-title="My Page">
Share
</span>
Accessing data-* attributes in JavaScript
If your JavaScript relied on the old attribute names, update the references:
<span id="share-btn" data-displaytext="ShareThis">Share</span>
<script>
const btn = document.getElementById('share-btn');
// Using getAttribute
const text = btn.getAttribute('data-displaytext');
// Using the dataset API
const textAlt = btn.dataset.displaytext;
</script>
Valid: Using a standard attribute instead
In some cases, the intent of displaytext is simply to provide a label or tooltip. If so, a standard attribute like title may be more appropriate:
<span class="st_sharethis" title="ShareThis">Share</span>
Choose the approach that best matches your use case — data-* for custom data consumed by JavaScript, or a semantic HTML attribute if one already serves the purpose.
HTML has a defined set of global attributes (such as id, class, lang, and title) and element-specific attributes. Any attribute that isn’t part of these recognized sets will trigger a validation error. The st_title attribute is a proprietary, non-standard attribute that was used by older versions of the ShareThis sharing widget to pass metadata — specifically, the title of the content being shared.
The HTML5 specification introduced data-* attributes as the standard mechanism for embedding custom data on elements. These attributes allow developers to store arbitrary information without conflicting with the HTML spec. Newer versions of ShareThis and similar services have adopted this convention, but legacy code — especially in CMS themes, plugins, or modules — may still use the old non-standard format.
Using invalid attributes causes several problems:
- Standards compliance: The document fails W3C validation, which can indicate deeper markup quality issues.
- Future compatibility: Browsers are not required to handle non-standard attributes in any predictable way. Future browser updates could ignore or strip them.
- Maintainability: Non-standard attributes make code harder for other developers to understand and maintain.
- Accessibility tools: Screen readers and other assistive technologies rely on well-formed HTML. Invalid attributes can cause unexpected behavior in these tools.
To fix this, replace all proprietary ShareThis attributes with their data-* equivalents. For example, st_title becomes data-st-title, st_url becomes data-st-url, and displayText becomes data-st-displaytext. You should also update the ShareThis JavaScript library to a version that recognizes the new attribute format.
Examples
❌ Invalid: Using proprietary attributes
<span class="st_sharethis" st_title="My Article" st_url="https://example.com/article" displayText="ShareThis">
Share
</span>
This triggers validation errors for st_title, st_url, and displayText because none of these are valid HTML attributes.
✅ Valid: Using data-* attributes
<span class="st_sharethis" data-st-title="My Article" data-st-url="https://example.com/article" data-st-displaytext="ShareThis">
Share
</span>
All custom data is now stored in properly namespaced data-* attributes, which are fully compliant with the HTML5 specification.
✅ Valid: Using a button element with data-* attributes
If the element is interactive (e.g., it triggers a share action on click), consider using a <button> instead of a <span> for better accessibility:
<button type="button" class="st_sharethis" data-st-title="My Article" data-st-url="https://example.com/article">
Share this article
</button>
Fixing this in a CMS
If you’re using Drupal, WordPress, or another CMS with a ShareThis module or plugin:
- Update the plugin/module to the latest version — most have already migrated to data-* attributes.
- Check your theme templates for hardcoded ShareThis markup that may still use the old attribute format.
- Search your codebase for st_title, st_url, and displayText and replace them with data-st-title, data-st-url, and data-st-displaytext respectively.
- Update the ShareThis JavaScript to a version compatible with the new attribute names, and verify that sharing functionality still works after the change.
HTML has a defined set of global attributes (like class, id, title, lang, etc.) and element-specific attributes that are permitted by the specification. Any attribute that falls outside this set — such as st_url, st_title, or displayText — will trigger a validation error because the browser and the validator don’t recognize it as part of the HTML standard.
The st_url attribute, along with related attributes like st_title, st_via, and displayText, originated from early versions of the ShareThis social sharing library. These were proprietary attributes that the ShareThis JavaScript would read from the DOM to configure sharing behavior. While browsers generally ignore attributes they don’t understand (so the page may still appear to work), using non-standard attributes violates the HTML specification and can cause several problems:
- Standards compliance: Invalid HTML can lead to unpredictable behavior across different browsers and future browser versions.
- Accessibility: Screen readers and other assistive technologies may not handle non-standard attributes correctly, potentially causing confusion.
- Maintainability: Non-standard markup is harder for other developers to understand and maintain.
- SEO: Search engine crawlers may penalize or misinterpret pages with significant validation errors.
HTML5 introduced data-* attributes specifically to solve this problem. Any custom data you need to attach to an element can use this pattern — for example, data-st-url instead of st_url. The ShareThis library itself updated its integration to use data-* attributes in later versions, so modern implementations should already follow this pattern.
How to Fix
- Replace proprietary attributes with data-* equivalents: Convert st_url to data-st-url, st_title to data-st-title, displayText to data-display-text, and so on.
- Update your ShareThis integration: If you’re using an outdated version of ShareThis (or an outdated CMS module/plugin like an old Drupal integration), update to the latest version, which uses valid HTML5 attributes.
- Check your CMS templates: If the invalid attributes are hardcoded in a theme template or a content block, update them manually.
Examples
Invalid: Proprietary attributes on a <span>
<span class="st_facebook_large" displayText="Facebook" st_url="https://example.com" st_title="My Page Title"></span>
<span class="st_twitter_large" displayText="Twitter" st_url="https://example.com" st_title="My Page Title"></span>
This markup uses st_url, st_title, and displayText, none of which are valid HTML attributes.
Valid: Using data-* attributes instead
<span class="st_facebook_large" data-display-text="Facebook" data-st-url="https://example.com" data-st-title="My Page Title"></span>
<span class="st_twitter_large" data-display-text="Twitter" data-st-url="https://example.com" data-st-title="My Page Title"></span>
By prefixing each custom attribute with data-, the markup becomes valid HTML5. Note that you may also need to update the associated JavaScript to read from these new attribute names (e.g., using element.dataset.stUrl instead of element.getAttribute('st_url')).
Valid: Modern ShareThis integration
If you’re updating your ShareThis integration entirely, the modern approach uses a different markup pattern:
<div class="sharethis-inline-share-buttons" data-url="https://example.com" data-title="My Page Title"></div>
Modern versions of the ShareThis library expect data-* attributes by default, so upgrading the library and its associated markup is the cleanest solution. Check the ShareThis documentation for the latest recommended integration approach for your platform.
The span element is a generic inline container with no inherent semantics. On its own, it carries no meaning for assistive technologies. When you add ARIA attributes like aria-expanded or aria-valuenow to a span, you are signaling that the element represents an interactive widget — but the validator (and assistive technologies) need more context. Many ARIA attributes are only permitted on elements that have certain roles, and some roles require a specific set of attributes to function correctly.
For example, aria-valuenow is designed for range widgets like sliders and progress bars. According to the WAI-ARIA specification, if you use aria-valuenow, the element must also have aria-valuemin, aria-valuemax, and a role such as progressbar, slider, meter, or scrollbar. Similarly, aria-expanded is meant for elements with roles like button, combobox, link, or treeitem. Placing these attributes on a bare span without the corresponding role violates the ARIA rules and triggers this validation error.
This matters for several reasons:
- Accessibility: Screen readers rely on the role to determine how to present a widget to users. Without it, ARIA state attributes become meaningless or confusing.
- Standards compliance: The HTML specification integrates ARIA rules, and validators enforce that ARIA attributes are used in valid combinations.
- Browser behavior: Browsers use the role to build the accessibility tree. A span with aria-valuenow but no role may be ignored or misrepresented to assistive technology users.
How to fix it
- Add the correct role to the span, along with all attributes required by that role.
- Use a semantic HTML element instead of a span when one exists (e.g., <progress> or <button>).
- Remove unnecessary ARIA attributes if the span is purely decorative or the attributes were added by mistake.
If your span is purely visual (e.g., a decorative asterisk for required fields), don’t add state-related ARIA attributes to it. Instead, use aria-hidden="true" to hide it from assistive technologies, and place ARIA attributes on the actual form control.
Examples
Incorrect: aria-expanded on a span without a role
<span aria-expanded="false">Menu</span>
The validator reports the missing role because aria-expanded isn’t valid on a generic span.
Correct: Add a role (or use a button)
<span role="button" tabindex="0" aria-expanded="false">Menu</span>
Or, better yet, use a real button element:
<button aria-expanded="false">Menu</button>
Incorrect: aria-valuenow without the full set of range attributes and role
<span class="progress-indicator" aria-valuenow="50">50%</span>
Correct: Include the role and all required range attributes
<span role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">
50%
</span>
Or use the native <progress> element, which has built-in semantics:
<progress value="50" max="100">50%</progress>
Incorrect: aria-required on a decorative span
<label for="email">
Email
<span class="required" aria-required="true">*</span>
</label>
<input id="email" name="email" type="email">
The aria-required attribute belongs on the form control, not on the decorative asterisk.
Correct: Hide the decorative indicator and mark the input as required
<label for="email">
Email
<span class="required" aria-hidden="true">*</span>
</label>
<input id="email" name="email" type="email" aria-required="true">
If you also want screen readers to announce “required” as part of the label text, add visually hidden text:
<label for="email">
Email
<span aria-hidden="true">*</span>
<span class="visually-hidden">required</span>
</label>
<input id="email" name="email" type="email" required>
The key takeaway: whenever you use ARIA state or property attributes on a span, make sure the element also has the correct role and all companion attributes required by that role. When a native HTML element already provides the semantics you need — such as <button>, <progress>, or <meter> — prefer it over a span with ARIA, as native elements are more robust and require less additional markup.
The <span> element is an inline container used to mark up a portion of text or a group of inline elements, typically for styling or scripting purposes. Like most HTML elements, it requires both an opening <span> tag and a closing </span> tag. When the closing tag is missing, the browser’s HTML parser must determine where the element ends on its own. Different browsers may handle this differently, potentially wrapping more content inside the <span> than intended.
This is problematic for several reasons:
- Unexpected styling: If the <span> has CSS applied to it (via a class, id, or inline style), the styles may bleed into sibling or subsequent elements that were never meant to be affected.
- Broken document structure: An unclosed <span> inside a <p> element can cause the parser to implicitly close and reopen elements in unexpected ways, distorting the DOM tree.
- Accessibility concerns: Screen readers and assistive technologies rely on a well-formed DOM. An unclosed element can cause content to be grouped or announced incorrectly.
- Maintenance difficulty: Unclosed elements make the markup harder to read, debug, and maintain over time.
A common scenario is forgetting the closing tag when the <span> wraps only part of a paragraph’s text. Another frequent cause is mismatched or misordered nesting, where the closing tags appear in the wrong sequence.
Examples
Unclosed <span> inside a paragraph
The closing </span> is missing entirely, so the browser has to guess where the span ends:
<!-- ❌ Bad: unclosed <span> -->
<p><span class="highlight">I'm forgetting something</p>
<p>Life goes on</p>
Add the missing </span> before the content that shouldn’t be wrapped:
<!-- ✅ Good: <span> is properly closed -->
<p><span class="highlight">I'm forgetting something</span></p>
<p>Life goes on</p>
Incorrectly nested closing tags
Sometimes the closing tags are present but in the wrong order. Tags must be closed in the reverse order they were opened:
<!-- ❌ Bad: closing tags are misordered -->
<p><em><span class="note">Important text</em></span></p>
<!-- ✅ Good: tags closed in correct (reverse) order -->
<p><em><span class="note">Important text</span></em></p>
Multiple <span> elements with a missing close
When using several <span> elements in sequence, it’s easy to lose track:
<!-- ❌ Bad: second <span> is never closed -->
<p>
<span class="first-name">Jane</span>
<span class="last-name">Doe
</p>
<!-- ✅ Good: all <span> elements are closed -->
<p>
<span class="first-name">Jane</span>
<span class="last-name">Doe</span>
</p>
Tips for avoiding unclosed elements
- Indent consistently. Proper indentation makes it much easier to spot a missing closing tag.
- Write both tags at once. When you type <span>, immediately type </span> and then fill in the content between them.
- Use an editor with auto-closing and bracket matching. Most modern code editors will highlight unmatched tags.
- Validate regularly. Run your markup through the W3C HTML Validator often, especially after larger edits.
Ready to validate your sites?
Start your free trial today.