Socket
Book a DemoInstallSign in
Socket

@spectrum-web-components/shared

Package Overview
Dependencies
Maintainers
7
Versions
384
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@spectrum-web-components/shared

The `@spectrum-web-components/shared` package provides essential base classes, mixins, and utilities that support developing Spectrum Web Components. This package contains foundational tools for focus management, slot observation, accessibility enhancemen

Source
npmnpm
Version
1.11.0-snapshot.20251106093044
Version published
Weekly downloads
16K
-12.95%
Maintainers
7
Weekly downloads
 
Created
Source

Overview

The @spectrum-web-components/shared package provides essential base classes, mixins, and utilities that support developing Spectrum Web Components. This package contains foundational tools for focus management, slot observation, accessibility enhancements, and other common functionality used across the component library.

Usage

See it on NPM! How big is this package in your project?

yarn add @spectrum-web-components/shared

Individual base classes, mixins, and utilities can be imported as follows:

import {
    Focusable,
    FocusVisiblePolyfillMixin,
    getActiveElement,
    getDeepElementFromPoint,
    LikeAnchor,
    ObserveSlotPresence,
    ObserveSlotText,
} from '@spectrum-web-components/shared';

Exported Classes, Mixins, and Utilities

Export Type Description getActiveElement() Utility Find the active element, including shadow DOM getDeepElementFromPoint() Utility Deepest element at coordinates Focusable Base class Focus management for custom elements LikeAnchor Mixin Anchor-like properties and rendering FocusVisiblePolyfillMixin Mixin Polyfill for :focus-visible support ObserveSlotPresence Mixin Observe presence of slotted content ObserveSlotText Mixin Observe text changes in slots

Utilities

getDeepElementFromPoint

The getDeepElementFromPoint method allows you to obtain the deepest possible element at given coordinates on the current page. The method will step into any available shadowRoots until it reaches the first element with no shadowRoot or no children available at the given coordinates.

When to use: Use this when you need to find the actual target element at specific coordinates, especially when working with shadow DOM where document.elementFromPoint() might not give you the deepest element.

import { getDeepElementFromPoint } from '@spectrum-web-components/shared';

const element = getDeepElementFromPoint(x, y);

getActiveElement

Use this helper to find an activeElement in your component.

When to use: Use this when you need to determine which element currently has focus, especially in components with shadow DOM where document.activeElement might not give you the correct element.

import { getActiveElement } from '@spectrum-web-components/shared';

const activeEl = getActiveElement(this);

Base classes

Focusable

The Focusable subclass of SpectrumElement adds helper methods and lifecycle coverage to support passing focus to a container element inside of a custom element. The Focusable base class handles tabindex setting into shadowed elements automatically and is based heavily on the aybolit delegate-focus-mixin.

When to use: Use this base class when creating custom elements that need to delegate focus to an internal element (like a button or input) while maintaining proper tabindex management and accessibility.

import { Focusable } from '@spectrum-web-components/shared';
import { html, TemplateResult } from '@spectrum-web-components/base';

class FocusableButton extends Focusable {
    public get focusElement(): HTMLElement {
        return this.shadowRoot.querySelector('#button') as HTMLElement;
    }

    protected override render(): TemplateResult {
        return html`
            <button id="button">
                Focus for this button is being managed by the `Focusable` base class.
            </button>
        `;
    }
}

Mixins

LikeAnchor

Mix download, label, href, target, rel, and referrerpolicy properties into your element to allow it to act more like an HTMLAnchorElement. It also provides a renderAnchor method for rendering anchor elements.

When to use: Use this mixin when creating custom elements that need to behave like links or buttons with link-like functionality, such as action buttons that can navigate to URLs.

import { LikeAnchor } from '@spectrum-web-components/shared';
import { ReactiveElement, html, TemplateResult } from '@spectrum-web-components/base';

class MyLinkElement extends LikeAnchor(ReactiveElement) {
    protected render(): TemplateResult {
        return this.renderAnchor({
            id: 'my-anchor',
            className: 'my-link',
            anchorContent: html`<slot></slot>`,
        });
    }
}

FocusVisiblePolyfillMixin

This mixin coordinates with the focus-visible polyfill to ensure proper behavior across browsers. Learn more about the polyfill that powers this.

When to use: Use this mixin when you need to leverage :focus-visible-based selectors in your CSS.

import { FocusVisiblePolyfillMixin } from '@spectrum-web-components/shared';

class MyElement extends FocusVisiblePolyfillMixin(HTMLElement) {
    // Your element now supports `:focus-visible` selectors and coordinates with the polyfill
}

ObserveSlotPresence

When working with styles that are driven by the conditional presence of <slot>s in a component's shadow DOM, you will need to track whether light DOM that is meant for that slot exists. Use the ObserveSlotPresence mixin to target specific light DOM to observe the presence of and trigger this.requestUpdate() calls when content fulfilling that selector comes in and out of availability.

When to use: Use this mixin when you need to conditionally render UI or apply styles based on whether specific slotted content is present. Common use cases include showing/hiding labels, icons, or wrapper elements.

import { ObserveSlotPresence } from '@spectrum-web-components/shared';
import { ReactiveElement, html, TemplateResult } from '@spectrum-web-components/base';

class ObserveSlotPresenceElement extends ObserveSlotPresence(
    ReactiveElement,
    '[slot="conditional-slot"]'
) {
    // Translate the mixin properties into locally understandable language
    protected get hasConditionalSlotContent() {
        return this.slotContentIsPresent;
    }

    protected override render(): TemplateResult {
        return html`
            <button id="button">
                ${this.hasConditionalSlotContent
                    ? html`<slot name="conditional-slot"></slot>`
                    : html``
                }
            </button>
        `;
    }

    protected updated(): void {
        console.log(this.slotContentIsPresent); // => true when <observing-slot-presence-element><div slot="conditional-slot"></div></observing-slot-presence-element>
    }
}

customElements.define('observing-slot-presence-element', ObserveSlotPresenceElement);

ObserveSlotText

When working with <slot>s and their slotchange event, you will have the opportunity to capture when the nodes and/or elements in your element are added or removed. However, if the textContent of a text node changes, you will not receive the slotchange event because the slot hasn't actually received new nodes and/or elements in the exchange. When working with a lit-html binding <your-element>${text}</your-element> that means you will not receive a slotchange event when the value of text goes from text = '' to text = 'something' or the other way. In these cases the ObserveSlotText can be leveraged to apply a mutation observer onto your element that tracks characterData mutations so that you can respond as desired.

When to use: Use this mixin when you need to detect changes in text content within slots, especially for dynamic text that changes after the initial render. Useful for components that need to react to text content changes for layout or styling purposes.

import { ObserveSlotText } from '@spectrum-web-components/shared';
import { ReactiveElement, html, TemplateResult } from '@spectrum-web-components/base';

class ObserveSlotTextElement extends ObserveSlotText(ReactiveElement) {
    protected override render(): TemplateResult {
        return html`
            <button id="button">
                <slot
                    id="observing-slot"
                    @slotchange=${this.manageTextObservedSlot}
                ></slot>
            </button>
        `;
    }

    protected updated(): void {
        console.log(this.slotHasContent); // => true when <observing-slot-text-element>Text</observing-slot-text-element>
    }
}

customElements.define('observing-slot-text-element', ObserveSlotTextElement);

For named slots, you can supply the name of the slot as the second argument:

class ObserveSlotTextElement extends ObserveSlotText(ReactiveElement, 'button-label') {
    protected override render(): TemplateResult {
        return html`
            <button id="button">
                <slot
                    name="button-label"
                    @slotchange=${this.manageObservedSlot}
                    @slotchange=${this.manageTextObservedSlot}
                ></slot>
            </button>
        `;
    }
}

Keywords

design-system

FAQs

Package last updated on 06 Nov 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts