Contact Us

Interactive Components

DOC-00043 reference implementor, developer

This page documents the interactive components available in the core theme. All components are CORE-OWNED, consume --st-* semantic tokens, and use vanilla TypeScript for interactivity with no external CDN dependencies.

Who this is for

  • Implementors placing accordions, tabs, tooltips, or media embeds in page content
  • Developers extending interactive component behavior or building new vanilla JS components

Accordion

File: src/core/components/ui/Accordion.astro File: src/core/components/ui/AccordionItem.astro

Single-expand accordion driven by shared vanilla JS state in the <Accordion> parent. Panel expand/collapse is animated via CSS grid-template-rows transitions.

Props — Accordion

PropTypeRequiredDefaultNotes
variant"default" | "faq" | "details"no"default"”faq” renders <dl> wrapper; “details” renders native <details>/<summary>
defaultOpennumberno1-based id of the item to open on load
triggerSizestringnoVisual font size for all triggers. Flows via CSS variable
classstringnoAdditional CSS classes

Props — AccordionItem

PropTypeRequiredDefaultNotes
variant"default" | "faq" | "details"no"default"Must match parent Accordion variant
idnumberyesUnique integer within the accordion (1-based)
titlestringyesPanel trigger label
headingLevel1–6no3Heading wrapping the trigger. Ignored in faq mode
triggerSizestringnoPer-item override of Accordion-level triggerSize

Usage

---
import Accordion from "@core/components/ui/Accordion.astro";
import AccordionItem from "@core/components/ui/AccordionItem.astro";
---

<Accordion defaultOpen={1}>
  <AccordionItem id={1} title="First item">
    <p>Panel content here.</p>
  </AccordionItem>
  <AccordionItem id={2} title="Second item">
    <p>Another panel.</p>
  </AccordionItem>
</Accordion>

Behavior

  • Only one panel is open at a time. Clicking an open panel’s trigger closes it.
  • defaultOpen sets the initially open item by its id prop (1-based integer).
  • The chevron icon rotates 180° when expanded.
  • Panel open/close is animated via CSS grid-template-rows transitions.
  • DOM IDs are generated with crypto.randomUUID() — safe to use multiple accordions on one page.

Accessibility

  • Trigger is a <button type="button"> wrapped in a heading (h3 by default).
  • aria-expanded on the trigger reflects the open/closed state.
  • aria-controls on the trigger references the panel element.
  • Panel has role="region" and aria-labelledby pointing to the trigger.

FAQ Variant

Set variant="faq" on both <Accordion> and each <AccordionItem> to render FAQ-appropriate semantic HTML using definition lists (<dl>, <dt>, <dd>) instead of generic <div> and heading wrappers.

Element mapping:

Roledefaultfaq
Container<div><dl>
Trigger wrapper<h1><h6><dt>
Panel wrapper<div><dd>

When variant="faq", the headingLevel prop is ignored — <dt> replaces the heading element. The panel omits role="region" since <dd> is already semantically associated with its <dt>.

---
import Accordion from "@core/components/ui/Accordion.astro";
import AccordionItem from "@core/components/ui/AccordionItem.astro";
---

<Accordion variant="faq">
  <AccordionItem variant="faq" id={1} title="What services do you offer?">
    <p>We offer web design, development, and SEO services.</p>
  </AccordionItem>
  <AccordionItem variant="faq" id={2} title="How long does a project take?">
    <p>Most projects are completed within 4–8 weeks.</p>
  </AccordionItem>
</Accordion>

FAQPage JSON-LD structured data is handled separately at the page level.

Trigger Size

The triggerSize prop controls the visual font size of trigger text independently from the semantic heading level. Set it on <Accordion> to apply to all items; set it on <AccordionItem> to override a single item.

Size scale: "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" (same as the Heading primitive).

Cascade: per-item triggerSize > Accordion triggerSize > inherited from wrapper element (heading size in default mode, body text in faq mode).

<Accordion triggerSize="sm">
  <AccordionItem id={1} title="Small trigger">
    <p>All items use sm.</p>
  </AccordionItem>
  <AccordionItem id={2} title="Large override" triggerSize="2xl">
    <p>This item overrides to 2xl.</p>
  </AccordionItem>
</Accordion>

Details Variant

Set variant="details" on both <Accordion> and each <AccordionItem> to render native <details>/<summary> elements. This variant uses zero JavaScript — the browser handles open/close natively.

Key differences from default/FAQ variants:

Behaviordefault / FAQdetails
Open/closeJS-driven single-expandNative <details> (multi-open allowed)
AnimationCSS grid-template-rows transitionSnap open/close (native <details>)
JavaScriptVanilla JS handlerZero JS
defaultOpenAccordion-level (1-based id)Per-item via <details open> attribute

Behavior: Multiple panels can be open simultaneously — this is expected native <details> behavior and an approved divergence from the single-expand behavior of default and FAQ variants.

---
import Accordion from "@core/components/ui/Accordion.astro";
import AccordionItem from "@core/components/ui/AccordionItem.astro";
---

<Accordion variant="details">
  <AccordionItem variant="details" id={1} title="What is this?">
    <p>Panel content using native details/summary.</p>
  </AccordionItem>
  <AccordionItem variant="details" id={2} title="How does it work?" defaultOpen>
    <p>This panel starts open via the native open attribute.</p>
  </AccordionItem>
</Accordion>

Tabs

File: src/core/components/ui/Tabs.astro File: src/core/components/ui/TabPanel.astro

Tabs powered by a vanilla TypeScript controller. The controller handles all ARIA roles, keyboard navigation, and panel visibility automatically. Tab buttons are generated from the tabs string array; panel content goes in <TabPanel> children in matching order.

Props — Tabs

PropTypeRequiredDefaultNotes
tabsstring[]yesOrdered tab labels. Must match <TabPanel> count
orientation"horizontal" | "vertical"no"horizontal"Layout and aria-orientation value
classstringnoAdditional CSS classes

Props — TabPanel

PropTypeRequiredDefaultNotes
classstringnoAdditional CSS classes

Usage

---
import Tabs from "@core/components/ui/Tabs.astro";
import TabPanel from "@core/components/ui/TabPanel.astro";
---

<Tabs tabs={["Overview", "API"]} orientation="horizontal">
  <TabPanel><p>Overview content.</p></TabPanel>
  <TabPanel><p>API reference.</p></TabPanel>
</Tabs>

Behavior

  • First tab is selected automatically by the vanilla JS controller.
  • Horizontal tabs use the “Minimal” underline style (bottom-border indicator on the active tab).
  • Vertical tabs use a sidebar highlight style (active tab receives a soft background).
  • Keyboard navigation: Left/Right arrows for horizontal, Up/Down for vertical; Home/End jump to first/last. Focus wraps at boundaries.
  • Bottom-border indicator for horizontal tabs uses scoped CSS (plain border-bottom) to avoid Tailwind v4 --tw-border-style variable issues.

Accessibility

  • All ARIA attributes (role="tablist", role="tab", role="tabpanel", aria-selected, aria-controls, aria-labelledby, aria-orientation, tabindex) are managed by the vanilla JS controller.
  • Base outline: none on tab buttons prevents browser default focus outlines from programmatic .focus() calls; :focus-visible scoped CSS restores a keyboard-only focus ring using project focus tokens.

Tooltip

File: src/core/components/ui/Tooltip.astro

Hover/focus tooltip using vanilla JS visibility toggling with CSS absolute positioning. Does not use the CSS popover API (which would promote the element to the top layer and break position: absolute).

Props

PropTypeRequiredDefaultNotes
contentstringyesTooltip text
placement"top" | "bottom" | "start" | "end"no"top"CSS placement side

Usage

---
import Tooltip from "@core/components/ui/Tooltip.astro";
import Button from "@core/components/primitives/Button.astro";
---

<Tooltip content="Saves your work" placement="top">
  <Button variant="secondary">Save</Button>
</Tooltip>

Behavior

  • Shows on mouseenter/focusin; hides on mouseleave/focusout or Escape key.
  • Opacity transition via CSS (duration-fast).
  • aria-describedby is set on slotted children at initialization time pointing to the tooltip span.
  • Limitation: does not auto-flip at viewport edges. Use placement to position away from edges manually.

Accessibility

  • Tooltip span has role="tooltip" and a stable id (UUID-based).
  • aria-describedby wired from trigger to tooltip at runtime.
  • Escape key dismissal via a keydown event listener on window.

CopyButton

File: src/core/components/ui/CopyButton.astro

Clipboard copy button with 2-second success feedback using the native Clipboard API.

Props

PropTypeRequiredDefaultNotes
textstringyesText to copy to clipboard on click
labelstringno"Copy"Button label in the default (pre-copy) state
classstringnoAdditional CSS classes

Usage

---
import CopyButton from "@core/components/ui/CopyButton.astro";
---

<CopyButton text="npm install some-package" label="Copy install command" />

Behavior

  • On click: copies text to clipboard, shows “Copied ✓” for 2 seconds, then reverts.
  • .catch() handler silently ignores failures (e.g., non-HTTPS context, iframe restrictions).
  • aria-label updates to “Copied!” while in the success state.

Code block auto-enhancement

The src/scripts/copy-code-blocks.ts script runs sitewide and automatically injects a copy button into every pre > code block at DOMContentLoaded. No per-block markup is needed. The injected button uses the same CSS class pattern as CopyButton for visual consistency.


PostShare

File: src/core/components/ui/PostShare.astro

Web Share API button with clipboard copy fallback for article sharing (PLN-6, REQ-00184). On supported browsers, opens the native OS share sheet. On unsupported browsers (Firefox desktop, older browsers), copies the article URL to clipboard with 2-second visual confirmation.

Props

PropTypeRequiredDefaultNotes
urlstringyesCanonical URL to share
titlestringyesArticle title for the Web Share API payload
textstringyesArticle description for the Web Share API text param
classstringnoAdditional CSS classes

Usage

---
import PostShare from "@core/components/ui/PostShare.astro";
---

<PostShare
  url={Astro.url.href}
  title={entry.data.title}
  text={entry.data.description}
/>

Behavior

  • On click (Web Share API supported): opens the native OS share sheet with the article URL, title, and description. If the user cancels the share sheet (AbortError), the button silently returns to its default state.
  • On click (Web Share API unsupported): copies the article URL to clipboard, swaps the button text/icon to “Link copied” with a checkmark for ~2 seconds, then reverts.
  • .catch() on clipboard failure silently ignores errors (matching the CopyButton pattern).
  • The button is hidden by default until vanilla JS initializes — the control is not present in server-rendered HTML (zero JS footprint).

Site configuration

Controlled via webSharing in site config (see Site Configuration):

FieldTypeDefaultNotes
webSharing.enabledbooleantrueEnable/disable sitewide

Per-article opt-out

Add webSharing: false to article frontmatter to disable the share button on that article:

---
title: My Article
webSharing: false
---

Config precedence: frontmatter → site config → schema default (true).

Browser coverage

The Web Share API is supported on most mobile browsers and Chrome/Edge/Safari desktop. Firefox desktop and some older browsers receive the clipboard copy fallback. This is the accepted degradation path.

Accessibility

  • Dynamic aria-label: “Share this article” in default state, “Link copied” during feedback state.
  • Keyboard-operable: standard <button> element, activates with Enter or Space.
  • Visible focus ring via the shared focus token utilities.
  • Hidden by default to prevent FOUC before JS initializes.

TocAside / TocInline — sticky sidebar + collapsible inline

See Table of Contents for the full three-component reference.

  • TocAside — sticky sidebar card with position: sticky, internal scroll container, and IntersectionObserver active-link highlighting. The topmost visible heading’s TOC link receives toc-list__link--active styling. Set activeLinks={false} to disable.
  • TocInline — collapsible in-page TOC with vanilla JS toggle. Starts expanded, no scroll or active links. Used in docs route main content header.

ScrollToTop

File: src/core/components/ui/ScrollToTop.astro

Fixed-position back-to-top button. Appears after scrolling 300px. Respects prefers-reduced-motion.

Props

PropTypeRequiredDefaultNotes
position"start" | "end"nositeConfig.scrollToTopPositionHorizontal position (start=left, end=right)

Site configuration

Controlled via two SiteConfig fields (see Site Configuration):

FieldTypeDefaultNotes
scrollToTopbooleantrueEnable/disable sitewide
scrollToTopPosition"start" | "end""end"Default horizontal position

Per-page opt-out

Add hideScrollToTop: true to any article or docs frontmatter to suppress the button on that page:

---
title: My Page
hideScrollToTop: true
---

Behavior

  • Initial visibility is set from window.scrollY on initialization (handles deep links and browser-restored scroll positions).
  • Scroll listener updates visibility as the user scrolls.
  • Click: smooth scroll to top, or instant scroll when prefers-reduced-motion: reduce is active.
  • Fade-in/out via CSS opacity transition (200ms).

Accessibility

  • aria-label="Back to top" on the button.
  • Receives a visible focus ring via the shared focus token utilities.
  • Hidden by default to prevent FOUC (Flash of Unstyled Content) before JS initializes.

YouTubeEmbed

File: src/core/components/ui/YouTubeEmbed.astro

Click-to-load YouTube video embed with a facade pattern. Zero third-party requests at page load — thumbnails are fetched at build time and served locally (REQ-00180, REQ-00104).

Props

PropTypeRequiredDefaultNotes
idstringyesBare video ID or full YouTube URL (watch, youtu.be, embed formats)
titlestringyesDescriptive title for iframe accessibility
eagerbooleannofalseBypass the facade — render the iframe directly with loading="eager"
aspectstringno"16/9"CSS aspect ratio string
classstringnoAdditional CSS classes

Usage

---
import YouTubeEmbed from "@core/components/ui/YouTubeEmbed.astro";
---

{/* Facade mode (default) — bare video ID */}
<YouTubeEmbed id="dQw4w9WgXcQ" title="Rick Astley — Never Gonna Give You Up" />

{/* Facade mode — full YouTube URL */}
<YouTubeEmbed
  id="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
  title="Rick Astley — Never Gonna Give You Up"
/>

{/* Eager mode — no facade, immediate iframe */}
<YouTubeEmbed id="dQw4w9WgXcQ" title="Rick Astley" eager />

{/* Custom aspect ratio */}
<YouTubeEmbed id="dQw4w9WgXcQ" title="Rick Astley (4:3)" aspect="4/3" />

Behavior

  • Facade mode (default): Renders a locally-served thumbnail with a play icon overlay. Clicking loads the YouTube iframe. No third-party requests until interaction.
  • Eager mode: Renders the YouTube iframe directly with loading="eager". No facade, no thumbnail fetch.
  • No-JS fallback: The facade is an <a> link to the YouTube video page with role="button". Without JavaScript, clicking navigates to YouTube.
  • Build-time thumbnails: Fetched from img.youtube.com at build time, cached in .astro/cache/youtube-thumbnails/, and served from /assets/youtube/. If YouTube is unreachable, a generic placeholder is used.
  • URL parsing: Accepts bare 11-character video IDs and common YouTube URL formats. Unrecognized formats produce a build-time error.

Accessibility

  • The facade <a> has role="button" and aria-label="Play: {title}".
  • Both Enter and Space activate the facade (per WAI-ARIA button pattern).
  • After the facade-to-iframe transition, focus moves to the iframe (tabindex="-1") with a wrapper fallback.
  • The iframe carries a descriptive title attribute.
  • Canonical focus ring pattern on the facade.

Privacy

Thumbnails are served from local build assets — no requests to YouTube, Google, or any third-party domain at page load. The YouTube iframe loads only after explicit user interaction (click or keyboard activation). This satisfies REQ-00104 (GDPR compliance).

The YouTube iframe uses referrerpolicy="strict-origin-when-cross-origin" (not no-referrer) because YouTube requires a referrer to validate embed authorization. This sends only the site origin, not the full page path.

BEM Hooks

.youtube-embed, .youtube-embed__facade, .youtube-embed__play-icon, .youtube-embed__iframe


Embed

File: src/core/components/ui/Embed.astro

Generic responsive iframe wrapper for arbitrary embeds. Privacy-safe by default with restrictive sandbox and referrerpolicy. Escape-hatch props available for embeds that need more capability.

Props

PropTypeRequiredDefaultNotes
srcstringyesURL of the content to embed
titlestringyesDescriptive title for iframe accessibility
aspectstringno"16/9"CSS aspect ratio string
allowFullscreenbooleannofalseAdd allowfullscreen attribute
sandboxstringno"allow-scripts allow-same-origin"Override default sandbox restrictions
allowstringnoPermissions Policy allow attribute
referrerPolicystringno"no-referrer"Override default referrer policy
classstringnoAdditional CSS classes

Usage

---
import Embed from "@core/components/ui/Embed.astro";
---

{/* Basic embed with safe defaults */}
<Embed
  src="https://www.openstreetmap.org/export/embed.html?..."
  title="Map of Central London"
/>

{/* With escape hatches */}
<Embed
  src="https://example.com/player"
  title="Video player"
  allowFullscreen
  sandbox="allow-scripts allow-same-origin allow-popups"
  allow="fullscreen; autoplay"
/>

Security Defaults

The component applies restrictive iframe attributes by default:

  • sandbox="allow-scripts allow-same-origin" — blocks popups, form submission, top-level navigation
  • referrerpolicy="no-referrer" — prevents sending the page URL to the third-party origin
  • No allow attribute — no camera, microphone, geolocation, etc.
  • No allowfullscreen — fullscreen is opt-in

Override any default via the corresponding prop when the embed provider requires it.

Accessibility

  • The iframe carries a descriptive title attribute sourced from the required title prop.
  • loading="lazy" defers iframe loading until the element approaches the viewport.

BEM Hooks

.embed, .embed__iframe

Manual accessibility test entries verified during the accessibility audit. Covers keyboard operability, screen-reader announcements, and ARIA semantics.

Accordion

Interaction Expected Behavior WCAG Criterion Test Method
Tab to the first Accordion header, press Enter or SpacePanel expands, content is visible, focus remains on the header2.1.1 Keyboard Keyboard
Press Enter or Space again on an expanded headerPanel collapses2.1.1 Keyboard Keyboard
Use Arrow Down/Up to move between accordion headersFocus moves between headers in order, each showing a visible focus ring2.1.1 Keyboard Keyboard
Inspect accordion headers and panels in DevToolsHeaders are button elements with aria-expanded toggling correctly; aria-controls references the panel; panels have role="region" with aria-labelledby4.1.2 Name, Role, Value Visual Inspection
Expand/collapse with prefers-reduced-motion: reduce enabledExpand/collapse transition is suppressed or instantaneous2.3.3 Animation from Interactions Visual Inspection
Expand and collapse accordion items with NVDA runningNVDA announces expanded/collapsed state and each header's label4.1.2 Name, Role, Value Screen Reader
Click a summary element in the details variant, then click anotherBoth panels remain open simultaneously. Native <details> behavior allows multi-open. No JS is involved.2.1.1 Keyboard Keyboard
Inspect the details variant in DevToolsRenders native <details>/<summary> elements. No data-slot="accordion" or data-slot="accordion-trigger" attributes. BEM hook classes (.accordion, .accordion__item) remain present.4.1.2 Name, Role, Value Visual Inspection

Tabs

Interaction Expected Behavior WCAG Criterion Test Method
Tab to the tab list, press Arrow Right to move between tabsFocus moves to the next tab, active tab changes, panel content updates2.1.1 Keyboard Keyboard
Press Arrow Left in the tab listFocus moves to the previous tab2.1.1 Keyboard Keyboard
Press Home and End in the tab listHome moves focus to the first tab; End moves focus to the last tab2.1.1 Keyboard Keyboard
Inspect tab list, tabs, and panels in DevToolsContainer has role="tablist"; tabs have role="tab" with aria-selected; panels have role="tabpanel" with aria-labelledby; tabindex managed correctly4.1.2 Name, Role, Value Visual Inspection
Navigate tabs with NVDA runningNVDA announces tab label, position (e.g., "tab 2 of 3"), and selected state4.1.2 Name, Role, Value Screen Reader

CopyButton

Interaction Expected Behavior WCAG Criterion Test Method
Tab to a CopyButton, verify focus is visibleCopyButton shows the canonical focus ring2.4.7 Focus Visible Keyboard
Press Enter on the CopyButtonVisual feedback indicates copy success; content is copied to clipboard2.1.1 Keyboard Keyboard
Focus the CopyButton with NVDA runningNVDA announces the button with a descriptive label4.1.2 Name, Role, Value Screen Reader

ScrollToTop

Interaction Expected Behavior WCAG Criterion Test Method
Scroll down until the ScrollToTop button appears, Tab to the buttonButton is focusable with visible focus ring2.4.7 Focus Visible Keyboard
Press Enter on the ScrollToTop buttonPage scrolls to the top, focus moves to a logical location2.1.1 Keyboard Keyboard
Focus the ScrollToTop button with NVDA runningNVDA announces the button with a descriptive label (e.g., "Back to top")4.1.2 Name, Role, Value Screen Reader

Tooltip

Interaction Expected Behavior WCAG Criterion Test Method
Tab to an element with a Tooltip, wait for it to appear on focusTooltip appears, remains visible while focus is on the trigger1.4.13 Content on Hover or Focus Keyboard
Press Escape while the tooltip is visibleTooltip dismisses, focus remains on the trigger element1.4.13 Content on Hover or Focus Keyboard
Hover the trigger, then move the pointer onto the tooltip contentTooltip remains visible while pointer is over it (hoverable); persists until pointer leaves or Escape is pressed1.4.13 Content on Hover or Focus Keyboard
Inspect the tooltip element and its trigger in DevToolsTooltip has role="tooltip"; trigger has aria-describedby referencing the tooltip4.1.2 Name, Role, Value Visual Inspection
Trigger the tooltip with prefers-reduced-motion: reduce enabledAny fade/slide animation is suppressed or instantaneous2.3.3 Animation from Interactions Visual Inspection
Focus the trigger with NVDA runningNVDA announces the tooltip content via aria-describedby4.1.2 Name, Role, Value Screen Reader

TocAside

Interaction Expected Behavior WCAG Criterion Test Method
Tab through the TocAside linksEach TOC link is focusable with visible focus ring2.4.7 Focus Visible Keyboard
Press Enter on a TOC linkPage scrolls to the referenced section, focus moves to the target heading2.1.1 Keyboard Keyboard
Inspect the TOC container in DevToolsTOC is wrapped in a nav element with an accessible label (e.g., aria-label="Table of contents")1.3.1 Info and Relationships Visual Inspection
Focus TOC links with NVDA runningNVDA announces each link with its text4.1.2 Name, Role, Value Screen Reader

YouTubeEmbed

Interaction Expected Behavior WCAG Criterion Test Method
Tab to the YouTubeEmbed facadeFacade receives visible focus ring. Screen reader announces "Play: [video title], button"2.4.7 Focus Visible Keyboard
Press Enter on the YouTubeEmbed facadeFacade is replaced by the YouTube iframe. Focus moves to the iframe or its wrapper element2.1.1 Keyboard Keyboard
Press Space on the YouTubeEmbed facadeFacade is replaced by the YouTube iframe (role=button elements must respond to Space)2.1.1 Keyboard Keyboard
Tab past the YouTube iframe after it loadsFocus moves to the next focusable element on the page — no focus trap2.1.2 No Keyboard Trap Keyboard
Inspect the YouTubeEmbed facade elementFacade <a> has role="button", aria-label="Play: [title]", and href pointing to youtube.com4.1.2 Name, Role, Value Visual Inspection
Inspect the YouTube iframe after clicking the facadeIframe has a descriptive title attribute matching the component's title prop4.1.2 Name, Role, Value Visual Inspection

Embed

Interaction Expected Behavior WCAG Criterion Test Method
Inspect the Embed iframe elementIframe has a descriptive title attribute matching the component's title prop4.1.2 Name, Role, Value Visual Inspection
REQ-00019 implemented Dynamic views shall provide standardized empty-state behavior.
REQ-00044 implemented The theme shall include a limited set of composite components.
REQ-00058 implemented The Back to Top control shall be accessible via keyboard and assistive technologies.
REQ-00066 implemented Table of contents generation shall be supported.
REQ-00180 implemented The content system shall support media embeds, with first-class support for YouTube embeds.
REQ-00184 implemented The theme shall provide a PostShare component that uses the Web Share API for native sharing with clipboard copy as the fallback for unsupported browsers.
REQ-00213 implemented YouTube embeds shall use a click-to-load facade pattern with build-time cached thumbnail images to prevent third-party data transfer before user interaction.
REQ-00214 implemented A generic Embed component shall apply restrictive iframe defaults (sandbox with allow-scripts and allow-same-origin only, no allow attributes by default, no allowfullscreen by default, referrerpolicy of strict-origin-when-cross-origin or stricter) with explicit opt-in escape hatches for permissions.
REQ-00215 implemented Media embed components shall degrade gracefully without JavaScript, providing direct links to the embedded content as fallback.
REQ-00240 implemented An Accordion component shall be provided with single-expand behavior, configurable default-open item (for CLS prevention), heading level control, reduced-motion support, and an FAQ variant that emits FAQPage structured data via the FAQSchema component.
REQ-00241 implemented A Tabs component shall be provided with horizontal and vertical orientation support, WAI-ARIA tabs pattern compliance via vanilla JS, and keyboard navigation (arrow keys for tab selection, Home/End for first/last).
REQ-00242 implemented A Tooltip component shall be provided with hover and focus triggers, role="tooltip" semantics, aria-describedby association between trigger and tooltip, Escape key to dismiss, and reduced-motion support for show/hide transitions.
REQ-00243 implemented A CopyButton component shall be provided for one-click clipboard copying with visual success feedback (icon swap with auto-revert after timeout), keyboard accessibility, and screen reader announcement of the copied state.

Search

Search across pages and articles. Use arrow keys to navigate results.

Search across pages and articles.

Loading search...

Search is unavailable. Please try again later.

    No results for ""

    Try different keywords or fewer words.