The is Attribute
The is Attribute
Section titled “The is Attribute”The is attribute allows you to create customized built-in elements by extending existing HTML elements with custom behavior through Web Components. Unlike autonomous custom elements, customized built-in elements inherit all the functionality and accessibility features of their base element.
Syntax
Section titled “Syntax”<button is="custom-button">Enhanced Button</button><input is="custom-input" type="text">Values
Section titled “Values”| Value | Description |
|---|---|
| Custom element name | Name of the customized built-in element (must contain a hyphen) |
Key Concepts
Section titled “Key Concepts”Customized Built-in vs Autonomous Custom Elements
Section titled “Customized Built-in vs Autonomous Custom Elements”Customized Built-in Element:
<!-- Extends native <button> --><button is="fancy-button">Click me</button>Autonomous Custom Element:
<!-- Completely new element --><fancy-button>Click me</fancy-button>Why Use Customized Built-in Elements?
Section titled “Why Use Customized Built-in Elements?”✓ Inherit native behavior: Get all browser defaults for free ✓ Accessibility: Native ARIA roles and keyboard support ✓ Progressive enhancement: Falls back to standard element if JS fails ✓ Semantic HTML: Keep semantic meaning of base element
Examples
Section titled “Examples”Enhanced Button
Section titled “Enhanced Button” Result
Auto-growing Textarea
Section titled “Auto-growing Textarea” Result
Validated Input
Section titled “Validated Input” Result
JavaScript Definition
Section titled “JavaScript Definition”Defining a Customized Built-in Element
Section titled “Defining a Customized Built-in Element”class MyButton extends HTMLButtonElement { constructor() { super(); // Always call super() first // Your custom initialization }
connectedCallback() { // Called when element is added to DOM }
disconnectedCallback() { // Called when element is removed from DOM }
attributeChangedCallback(name, oldValue, newValue) { // Called when observed attributes change }}
// Register the elementcustomElements.define('my-button', MyButton, { extends: 'button' // IMPORTANT: Specify base element});HTML Usage
Section titled “HTML Usage”<!-- Use with "is" attribute --><button is="my-button">Click Me</button>
<!-- Or create programmatically --><script>const btn = document.createElement('button', { is: 'my-button' });btn.textContent = 'Click Me';document.body.appendChild(btn);</script>Which Elements Can Be Extended?
Section titled “Which Elements Can Be Extended?”You can extend most HTML elements:
// Extend buttonclass FancyButton extends HTMLButtonElement { }customElements.define('fancy-button', FancyButton, { extends: 'button' });
// Extend inputclass MaskedInput extends HTMLInputElement { }customElements.define('masked-input', MaskedInput, { extends: 'input' });
// Extend selectclass SuperSelect extends HTMLSelectElement { }customElements.define('super-select', SuperSelect, { extends: 'select' });
// Extend divclass SmartDiv extends HTMLDivElement { }customElements.define('smart-div', SmartDiv, { extends: 'div' });
// Extend ulclass TodoList extends HTMLUListElement { }customElements.define('todo-list', TodoList, { extends: 'ul' });Best Practices
Section titled “Best Practices”1. Always Use a Hyphen in Name
Section titled “1. Always Use a Hyphen in Name”// ✓ Good: Contains hyphencustomElements.define('my-button', MyButton, { extends: 'button' });
// ✗ Bad: No hyphencustomElements.define('mybutton', MyButton, { extends: 'button' });2. Call super() in Constructor
Section titled “2. Call super() in Constructor”class MyElement extends HTMLButtonElement { constructor() { super(); // REQUIRED // Your code... }}3. Use for Progressive Enhancement
Section titled “3. Use for Progressive Enhancement”<!-- Falls back to regular button if JS fails --><button is="fancy-button">Still works without JS!</button>4. Preserve Native Functionality
Section titled “4. Preserve Native Functionality”class BetterButton extends HTMLButtonElement { constructor() { super(); // Add behavior, don't break existing functionality this.addEventListener('click', this.customBehavior.bind(this)); }
customBehavior() { // Additional functionality console.log('Custom behavior'); // Native click behavior still works }}Common Use Cases
Section titled “Common Use Cases”Auto-formatting Input
Section titled “Auto-formatting Input”class PhoneInput extends HTMLInputElement { constructor() { super(); this.addEventListener('input', this.formatPhone.bind(this)); }
formatPhone() { let value = this.value.replace(/\D/g, ''); if (value.length > 10) value = value.slice(0, 10);
if (value.length >= 6) { this.value = `(${value.slice(0, 3)}) ${value.slice(3, 6)}-${value.slice(6)}`; } else if (value.length >= 3) { this.value = `(${value.slice(0, 3)}) ${value.slice(3)}`; } else { this.value = value; } }}
customElements.define('phone-input', PhoneInput, { extends: 'input' });<input is="phone-input" type="tel" placeholder="Phone number">Copy Button
Section titled “Copy Button”class CopyButton extends HTMLButtonElement { constructor() { super(); this.addEventListener('click', this.copy.bind(this)); }
async copy() { const target = this.dataset.copyTarget; const element = document.getElementById(target);
if (element) { await navigator.clipboard.writeText(element.textContent); this.textContent = 'Copied!'; setTimeout(() => this.textContent = 'Copy', 2000); } }}
customElements.define('copy-button', CopyButton, { extends: 'button' });<pre id="code">console.log('Hello');</pre><button is="copy-button" data-copy-target="code">Copy</button>Limitations
Section titled “Limitations”Workarounds for Safari
Section titled “Workarounds for Safari”- Use autonomous custom elements instead
- Use a polyfill: @webcomponents/custom-elements
- Feature detection:
function supportsCustomizedBuiltInElements() { try { customElements.define('test-button', class extends HTMLButtonElement {}, { extends: 'button' }); return true; } catch { return false; }}
if (supportsCustomizedBuiltInElements()) { // Use customized built-in elements} else { // Use autonomous custom elements or fallback}Browser Support
Section titled “Browser Support”| Browser | Support |
|---|---|
| Chrome | 67+ |
| Firefox | 63+ |
| Edge | 79+ |
| Safari | ❌ Not supported |
Related Concepts
Section titled “Related Concepts”- Custom Elements API - Create custom HTML elements
- Shadow DOM - Encapsulated DOM trees
- Web Components - Reusable custom elements