standards-ui
Version:
A foundational design system built with native Web Components. Includes comprehensive TypeScript types, JSDoc documentation, and component examples.
203 lines (174 loc) • 6.7 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: ds-legend.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: ds-legend.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @file ds-legend.js
* @summary A custom Web Component that wraps a native `<legend>` element.
* @description
* The `ds-legend` component provides a styled and functional legend element
* for providing a caption or title for a fieldset. It should be used within
* `<ds-fieldset>` components to describe the group of form controls.
*
* - The content inside `<ds-legend>...</ds-legend>` is rendered via the default slot as the legend text.
* - Should be used as the first child of a `<ds-fieldset>` for proper semantics.
* - Supports ARIA attributes: `aria-label`, `aria-describedby` for accessibility.
* - Uses `part="legend"` for styling via Shadow DOM.
* - Warns in the console if no accessible name (text or `aria-label`) is provided.
* - No custom events are fired.
*
* @element ds-legend
*
* @slot - Renders the legend text content.
*
* @attr {string} aria-label - Accessible label for the legend element (overrides text content).
* @attr {string} aria-describedby - Reference to element(s) describing the legend.
*
* @note Uses `part="legend"` for styling via Shadow DOM.
* @note Warns if no accessible name (text or `aria-label`) is provided.
* @note Should be used as the first child of a `<ds-fieldset>` for correct semantics.
*
* @example
* <!-- Basic legend within fieldset -->
* <ds-fieldset>
* <ds-legend>Contact Information</ds-legend>
* <ds-label for="email">Email</ds-label>
* <ds-text-input type="email" id="email" name="email"></ds-text-input>
* </ds-fieldset>
*
* @example
* <!-- Legend with form controls -->
* <ds-fieldset>
* <ds-legend>Shipping Address</ds-legend>
* <ds-label for="street">Street Address</ds-label>
* <ds-text-input id="street" name="street"></ds-text-input>
* <ds-label for="city">City</ds-label>
* <ds-text-input id="city" name="city"></ds-text-input>
* <ds-label for="zip">ZIP Code</ds-label>
* <ds-text-input id="zip" name="zip"></ds-text-input>
* </ds-fieldset>
*
*
* <!-- Legend with radio button group -->
* <ds-fieldset>
* <ds-legend>Preferred Contact Method</ds-legend>
* <ds-radio name="contact" value="email" id="contact-email">Email</ds-radio>
* <ds-radio name="contact" value="phone" id="contact-phone">Phone</ds-radio>
* <ds-radio name="contact" value="mail" id="contact-mail">Mail</ds-radio>
* </ds-fieldset>
*/
import BaseComponent from './base-component.js';
class DsLegend extends BaseComponent {
constructor() {
// ARIA config for ds-legend
const ariaConfig = {
staticAriaAttributes: {},
dynamicAriaAttributes: [
'aria-label',
'aria-describedby'
],
requiredAriaAttributes: [],
referenceAttributes: ['aria-describedby'],
};
const template = document.createElement('template');
template.innerHTML = `
<style>
@import url('/src/styles/styles.css');
:host {
display: block;
}
.wrapper {
width: 100%;
}
</style>
<div class="wrapper">
<legend part="legend">
<slot></slot>
</legend>
</div>
`;
super({
template: template.innerHTML,
targetSelector: 'legend',
ariaConfig,
events: [],
observedAttributes: []
});
this.legend = this.shadowRoot.querySelector('legend');
}
static get observedAttributes() {
return ['aria-label', 'aria-describedby'];
}
attributeChangedCallback(name, oldValue, newValue) {
super.attributeChangedCallback(name, oldValue, newValue);
if (oldValue === newValue) return;
}
// ARIA property accessors
get ariaLabel() {
const value = this.legend.getAttribute('aria-label');
return value === null ? null : value;
}
set ariaLabel(val) {
if (val === null || val === undefined) {
this.legend.removeAttribute('aria-label');
} else {
this.legend.setAttribute('aria-label', val);
}
}
get ariaDescribedBy() {
const value = this.legend.getAttribute('aria-describedby');
return value === null ? null : value;
}
set ariaDescribedBy(val) {
if (val === null || val === undefined) {
this.legend.removeAttribute('aria-describedby');
} else {
this.legend.setAttribute('aria-describedby', val);
}
}
// Override validateARIA for legend-specific checks
validateARIA() {
const errors = super.validateARIA ? super.validateARIA() : [];
// Accessible name check: must have text or aria-label
const legendText = this.textContent.trim();
const ariaLabel = this.legend.getAttribute('aria-label');
if (!legendText && !ariaLabel) {
errors.push('Legend has no accessible name (text or aria-label required)');
}
return errors;
}
}
// Register the custom element
if (!customElements.get('ds-legend')) {
customElements.define('ds-legend', DsLegend);
}
// Export for use in other modules
export default DsLegend;</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="BaseComponent.html">BaseComponent</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Wed Aug 20 2025 19:54:53 GMT-0700 (Pacific Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>