npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ars-web-components

v3.1.0

Published

A collection of reusable web components built with TypeScript and ES modules

Readme

ARS Web Components

A collection of reusable web components built with TypeScript and ES modules.

⚠️ Breaking change in v3.0.0: component modules no longer register custom elements at import time. You must call registerArsWebComponents() before using any <ars-*> tag. See Registration below.

🚀 Live Demo

Check out the live demo.

Alternative: Download the repository and open index.html in a local web server.

Features

  • 🎯 TypeScript: Full type safety with generated .d.ts declarations
  • 🎨 CSS-friendly: Components are styling-agnostic, use your own CSS classes
  • ⚡ ES Modules: Modern module system with proper imports/exports
  • 🔧 Interactive Effects: Built-in pressed effects and animations
  • 📱 Touch Support: Full mobile and desktop interaction support
  • 🧪 Vitest Testing: 785 tests with jsdom environment
  • 🧹 ESLint: Flat-config linting for source, tests, and tool configs
  • 🔒 Proper Encapsulation: Private methods and static utilities for clean API design
  • 🤝 Mixin Coordination: Smart pointer coordination system for multiple gesture mixins
  • 📜 Mobile Scroll Management: Intelligent scroll prevention during gesture interactions

Architecture

Project Structure

ars-web-components/
├── src/                    # TypeScript source files
│   ├── components/         # Web components
│   │   ├── ars-button/
│   │   ├── ars-calendar/
│   │   ├── ars-candlestick-chart/
│   │   ├── ars-color-select/
│   │   ├── ars-data-roller/
│   │   ├── ars-dialog/
│   │   ├── ars-info-tile/
│   │   ├── ars-input/
│   │   ├── ars-line-chart/
│   │   ├── ars-page/
│   │   ├── ars-select/
│   │   ├── ars-table/
│   │   ├── ars-tabs/
│   │   ├── ars-toast/
│   │   ├── ars-toggle/
│   │   ├── chart-base/
│   │   └── web-component-base/
│   ├── mixins/             # Reusable mixins
│   │   ├── common/
│   │   ├── draggable-mixin/
│   │   ├── localized-mixin/
│   │   ├── pressed-effect-mixin/
│   │   ├── remote-call-mixin/
│   │   ├── roll-mixin/
│   │   ├── show-if-property-true-mixin/
│   │   └── swipeable-mixin/
├── demos/                  # Demo entry points and demo-only assets
│   └── css/                # Shared CSS for demos
├── dist/                   # Compiled JavaScript output (generated)
├── test/                   # Shared Vitest setup and mocks
├── tsconfig.json
├── vitest.config.ts
└── server.js               # Express dev server

TypeScript + Web Components

All components extend WebComponentBase (which extends HTMLElement) and are compiled from TypeScript to ES modules with full type declarations.

Chart components (ars-line-chart, ars-candlestick-chart) use WebGPU instanced rendering for high-performance visualization. Each frame submits 3 GPU draw calls instead of hundreds of sequential Canvas 2D method calls. A shared GPUDevice is created lazily on first use, or can be injected externally via ChartGPUContext.setDevice(device) for integration with engines like brainiac-engine.

import WebComponentBase from "../web-component-base/web-component-base.js";

class MyComponent extends WebComponentBase {
  static get observedAttributes() {
    return ["attr1", "attr2"];
  }

  connectedCallback() { /* lifecycle */ }
  attributeChangedCallback(name: string, oldVal: string, newVal: string) { /* ... */ }

  publicMethod() { /* component API */ }
}

Installation

npm install ars-web-components

Development Workflow

Live-reload demo development (recommended while editing)

Use Vite to serve the demos with automatic reload from src/ (no rebuild required on each edit):

npm run dev

Then open the printed local URL (for example http://127.0.0.1:8080/ or http://127.0.0.1:8081/).

Notes:

  • The demo pages still reference /dist/... paths, but the Vite dev server rewrites them to /src/... during development.
  • This keeps the demo HTML stable while enabling fast iteration.

Dist build verification (release/package path)

When you want to verify the published package output, rebuild the package:

npm run build

This regenerates dist/, which is what external consumers import.

Tests

Run the test suite:

npm test

Test files live alongside the source they cover (for easier navigation while editing components/mixins). Shared Vitest setup and mocks remain in test/.

Lint

Run the lint suite:

npm run lint

The lint configuration covers source files, colocated tests, and TypeScript tool config files through tsconfig.eslint.json.

Registration

Because the package is marked sideEffects: false, importing a component class does not register its custom element. Call registerArsWebComponents() once at application startup before any <ars-*> tag is rendered:

import { registerArsWebComponents } from "ars-web-components";

registerArsWebComponents();

For apps that only use a few components, register them manually instead to keep bundles smaller:

import { ArsButton } from "ars-web-components";

customElements.define("ars-button", ArsButton);

Design System Compatibility (Design-Agnostic by Default)

ars-web-components is intended to be design-system agnostic.

  • It should work with your own CSS/theme variables.
  • In the Dark Factory ecosystem (internal usage), the default pairing is the private ars-design-system.
  • If no design system is used, you can start from one of the lightweight fallback theme templates shipped in this package.

Recommended pairing (Dark Factory / internal usage)

Import order:

import "ars-design-system/styles.css";
import "ars-web-components/styles.css";

Then initialize the component library with your design adapter:

import {
  initializeArsWebComponents,
  registerArsWebComponents,
} from "ars-web-components";

registerArsWebComponents();
initializeArsWebComponents({
  designAdapter: {
    rootAttributes: { "data-theme": "my-app-theme" },
    cssVariables: {
      "--arswc-color-accent": "#2563eb"
    }
  }
});

The adapter contract is intentionally small and generic so applications can supply any design system.

Explicit default adapter (no external design system)

If you want an explicit non-Dark-Factory setup without custom adapters:

import {
  getArsWebComponentsDefaultAdapter,
  initializeArsWebComponents,
  registerArsWebComponents,
} from "ars-web-components";

registerArsWebComponents();
initializeArsWebComponents({
  designAdapter: getArsWebComponentsDefaultAdapter("dark"),
});

This keeps initialization explicit while still providing a simple starter theme.

Brainiac Engine Embedding

ars-web-components can be mounted inside brainiac-engine DOM overlays as agent presentations.

Embedding guidelines:

  • Prefer components that can operate inside a provided host container instead of assuming document.body.
  • Prefer local/internal routing when embedding page containers inside an engine overlay.
  • Prefer owner-document scoped listeners over hard-coded global window references.
  • Prefer declarative event wiring and direct template rendering over dynamic string evaluation.

Current component support for engine embedding:

  • ars-calendar
    • supports global-events-enabled="false" so embedded hosts can opt out of global window events
  • ars-dialog
    • static notify(...) and dialog(...) accept an optional mount-target options object
  • ars-page
    • supports routing-mode="internal" for local navigation without browser history ownership

Hardening notes for embedded hosts:

  • web-component-base no longer uses eval to wire DOM events
  • ars-dialog and ars-color-select now render templates directly instead of evaluating template strings
  • embedded integrations should prefer explicit host references and typed data over raw HTML/script injection patterns

For comprehensive embedding guidance including mount/unmount lifecycle, event forwarding, and design adapter usage in iframes/shadow roots, see docs/EMBEDDING.md.

For the release process checklist, see docs/PUBLISH_CHECKLIST.md.

Custom Design System Contract (--arswc-*)

ars-web-components components read library-level design variables (--arswc-*) set by the active design adapter.

When a custom design system initializes the library, it should set some or all of these variables on the document root (or another shared scope):

Recommended core variables:

  • --arswc-color-bg
  • --arswc-color-surface
  • --arswc-color-border
  • --arswc-color-text
  • --arswc-color-muted
  • --arswc-color-accent
  • --arswc-color-accent-contrast
  • --arswc-radius-sm
  • --arswc-radius-md
  • --arswc-shadow-sm
  • --arswc-font-family-sans
  • --arswc-font-family-mono

Resolution priority in components:

  1. component-specific CSS variables (for example --ars-calendar-*)
  2. library design variables (--arswc-*) from the active adapter
  3. hardcoded component fallback values

This makes the library design-system agnostic while keeping integration predictable.

Design Contract Coverage

All components resolve their default styling through the library design contract (--arswc-*) before falling back to hardcoded values.

Core tokens (used by most components):

  • --arswc-color-bg, --arswc-color-surface, --arswc-color-border
  • --arswc-color-text, --arswc-color-muted, --arswc-color-accent, --arswc-color-accent-contrast
  • --arswc-radius-sm, --arswc-radius-md, --arswc-shadow-sm
  • --arswc-font-family-sans, --arswc-font-family-mono

Semantic color tokens (added in 1.0.0):

  • --arswc-color-danger — destructive actions, error states (button, toast, input validation)
  • --arswc-color-success — success confirmation (toast, toggle on state)
  • --arswc-color-warning — warning states (toast)
  • --arswc-color-disabled, --arswc-color-disabled-bg — disabled element foreground/background

Typography and spacing tokens (added in 1.0.0):

  • --arswc-font-size-sm, --arswc-font-size-md, --arswc-font-size-lg
  • --arswc-spacing-xs through --arswc-spacing-xl
  • --arswc-transition-duration, --arswc-focus-ring

Components remain independently overridable through their own component-specific CSS variables (for example --ars-calendar-*).

Fallback templates (no design system)

Choose one small generic template and then override values in your app:

import "ars-web-components/theme-default-dark.css";
import "ars-web-components/styles.css";

or

import "ars-web-components/theme-default-light.css";
import "ars-web-components/styles.css";

These fallback templates are intentionally minimal. They exist to make adoption easy, not to define a complete visual identity.

Usage

Method 1: ES Module Import (Recommended)

import { ArsCalendar } from "ars-web-components";

Method 2: Direct Script Import

For projects that need to load components directly without bundling:

<script type="module" src="./node_modules/ars-web-components/dist/index.js"></script>

Components

Component Inventory

| Component | Tag | Status | Description | |---|---|---|---| | Button | <ars-button> | Stable | Interactive button with variant, size, disabled, loading | | Toggle | <ars-toggle> | Stable | Boolean switch control with keyboard support | | Input | <ars-input> | Stable | Text input with label, validation, clearable | | Color Select | <ars-color-select> | Stable | Carousel color picker with keyboard navigation | | Toast | <ars-toast> | Stable | Notification toast with stacking and auto-dismiss | | Tabs | <ars-tabs> | Stable | Tabbed navigation with 4 placement options | | Select | <ars-select> | Stable | Dropdown select with search and multi-select | | Table | <ars-table> | Stable | Data table with sorting, selection, virtual scroll | | Calendar | <ars-calendar> | Stable | Date selection and event management | | Dialog | <ars-dialog> | Stable | Modal dialog with confirmation and notification modes | | Data Roller | <ars-data-roller> | Stable | Animated cycling data display | | Info Tile | <ars-info-tile> | Stable | Structured information card for dashboards | | Line Chart | <ars-line-chart> | Stable | WebGPU-rendered line chart | | Candlestick Chart | <ars-candlestick-chart> | Stable | WebGPU-rendered financial OHLC candlestick chart | | Page Router | <ars-page> | Stable | Component-based routing | | Relational Node | <ars-relational-node> | Deprecated | Use <ars-info-tile> instead |

ArsButton

Styled, accessible button with variant, size, and state support.

<ars-button variant="primary" size="md">Click Me</ars-button>
<ars-button variant="danger" disabled>Disabled</ars-button>
<ars-button loading>Loading...</ars-button>

Attributes: variant (primary/secondary/danger/ghost), size (sm/md/lg), disabled, loading, type (button/submit/reset)

Slots: default (label), prefix, suffix

Events: ars-button:click — detail: { variant }

ArsToggle

Boolean switch control with keyboard support.

<ars-toggle label="Dark mode" checked></ars-toggle>

Attributes: checked, disabled, label, label-position (start/end)

Events: ars-toggle:change — detail: { checked }

ArsInput

Text input with label, validation, and clearable state.

<ars-input label="Email" type="email" placeholder="[email protected]" required></ars-input>
<ars-input label="Search" type="search" clearable></ars-input>

Attributes: type, value, placeholder, label, error, disabled, readonly, clearable, min, max, step, pattern, required

Slots: prefix, suffix

Events: ars-input:input, ars-input:change, ars-input:clear

ArsToast

Notification toast with severity levels and stacking.

import { ArsToast } from "ars-web-components";

ArsToast.show("Operation complete!", {
  severity: "success",
  duration: 4000,
  position: "top-right",
});

Static API: ArsToast.show(message, options) — options: severity, duration, dismissible, position, progress, mountTarget, targetDocument

Attributes: message, severity (info/success/warning/error), duration, dismissible, progress, open

Events: ars-toast:dismiss — detail: { reason }

ArsTabs

Tabbed navigation with companion <ars-tab-panel>.

<ars-tabs>
  <ars-tab-panel tab-id="overview" label="Overview">Content here</ars-tab-panel>
  <ars-tab-panel tab-id="settings" label="Settings">Settings here</ars-tab-panel>
</ars-tabs>

Attributes: active-tab, placement (top/bottom/start/end)

Events: ars-tabs:change — detail: { activeTab, previousTab }

ArsSelect

Dropdown select with search, groups, and multi-select.

const select = document.querySelector("ars-select");
select.options = [
  { value: "apple", label: "Apple" },
  { value: "banana", label: "Banana", group: "Tropical" },
];

Attributes: value, placeholder, label, disabled, searchable, multiple, error

Events: ars-select:change, ars-select:open, ars-select:close

ArsTable

Data table with sorting, selection, and virtual scrolling.

const table = document.querySelector("ars-table");
table.columns = [
  { key: "name", label: "Name" },
  { key: "age", label: "Age", align: "end" },
];
table.data = [
  { name: "Alice", age: 30 },
  { name: "Bob", age: 25 },
];

Attributes: selectable (none/single/multiple), sortable, striped, compact, virtual-scroll, auto-sort

Events: ars-table:sort, ars-table:select, ars-table:row-click

ArsCalendar

Interactive calendar component with full customization support.

<ars-calendar
  id="myCalendar"
  localized_abbreviated_days='["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]'
  localized_months='["January","February","March",...,"December"]'
  localized_today="Today"
  css-vars='{"ars-calendar-bg": "#f0f0f0", "ars-calendar-header-bg": "#333"}'
></ars-calendar>

Attributes:

  • localized_abbreviated_days: JSON array of localized day abbreviations
  • localized_months: JSON array of localized month names
  • localized_today: Localized text for "Today" button
  • custom-css: Custom CSS string to add to component styles
  • css-vars: JSON object of CSS custom properties for theming

Methods:

  • addEvent(event): Add an event to the calendar
  • removeEvent(event): Remove an event from the calendar
  • changeEvent(date, newText, newColor): Modify an existing event
  • selectDate(day, month, year): Programmatically select a date
  • setSelectedDateToToday(): Select today's date
  • setCustomTemplate(templateFunction): Provide custom HTML template
  • setCSSVars(cssVarsObject): Set CSS variables programmatically
  • getCSSVars(): Get current CSS variables

Events:

  • ars-calendar:daySelected: Fired when a date is selected

CSS Customization:

The calendar supports extensive theming through CSS variables:

ars-calendar {
  --ars-calendar-bg: #ffffff;
  --ars-calendar-shadow: 0px 3px 3px rgba(0, 0, 0, 0.25);
  --ars-calendar-border-radius: 5px;
  --ars-calendar-header-bg: linear-gradient(to bottom, #b32b0c, #cd310d);
  --ars-calendar-header-height: 34px;
  --ars-calendar-header-color: #fff;
  --ars-calendar-cell-width: 30px;
  --ars-calendar-cell-height: 30px;
  /* ... and many more */
}

ArsDialog

Modal dialog component for user interactions. Supports custom content, styling with backdrop management, and both confirmation and notification modes.

// Open a dialog with confirmation buttons and custom content
const result = await ArsDialog.dialog(
  `<form><label>Name: <input id='name'></label></form>`,
  "Dialog Title"
);
if (result) {
  const name = result.querySelector("#name").value;
  // ...
}

// Show a notification dialog
await ArsDialog.notify("Operation complete!", "Success");

Attributes:

  • custom-css: Custom CSS string to add to dialog styles
  • css-vars: JSON object of CSS custom properties for theming

Methods:

  • setCSSVars(cssVarsObject): Set CSS variables programmatically
  • getCSSVars(): Get current CSS variables

Styling & Theming:

  • Dialog supports extensive theming via CSS variables (see ars-dialog-css.js)
  • Form elements (input, select, textarea) are styled by default, even for light DOM content injected as HTML
  • Content area is fully responsive and prevents overflow

Light DOM Form Styling:

If you inject form elements as raw HTML (light DOM) into the dialog, ARS Dialog will automatically inject a <style> tag with form element CSS into the content area, ensuring consistent styling for input, select, and textarea.

Events:

  • Dialog returns the content DOM element (for confirmation dialogs) or null/false if cancelled

Example:

const result = await ArsDialog.dialog('<input id="myInput">', "Enter Value");
if (result) {
  alert(result.querySelector("#myInput").value);
}

ArsColorSelect

Carousel-based color picker with spectrum-ordered swatches and keyboard navigation.

<ars-color-select color="#3B82F6" visible-count="7"></ars-color-select>

Features:

  • Horizontal carousel strip of circular swatches in spectrum order (red → orange → yellow → green → blue → purple → neutrals)
  • Navigation buttons and position track indicator
  • Keyboard navigation: Arrow Left/Right, Home, End
  • ARIA listbox semantics with role="option" and aria-selected
  • Custom palette via palette property, swatch sizes (sm/md/lg)
  • prefers-reduced-motion support

Attributes: color, palette (JSON array), swatch-size (sm/md/lg), disabled, visible-count

Events: ars-color-select:change — detail: { id, color, previousColor }

Usage Example:

const picker = document.querySelector("ars-color-select");
picker.palette = ["#FF0000", "#00FF00", "#0000FF"];
picker.addEventListener("ars-color-select:change", (e) => {
  console.log(`Selected: ${e.detail.color}`);
});

ArsPage & ArsPageController

Component-based router and navigation controls for web applications, using the new remote-call API for inter-component communication.

ArsPage

<ars-page
  id="my-router"
  default-page="home"
  routes='{"home":"/","about":"/about","contact":"/contact"}'
>
  <div id="home">Home page content</div>
  <div id="about">About page content</div>
  <div id="contact">Contact page content</div>
</ars-page>

Attributes:

  • default-page: The page to show initially

ArsPageController

<ars-page-controller target-page="my-router">
  <nav>
    <button data-page="home">Home</button>
    <button data-page="about">About</button>
    <button data-page="contact">Contact</button>
  </nav>
</ars-page-controller>

Attributes:

  • target-page: The ID of the ars-page component to control

Features:

  • Component-based routing
  • Custom navigation markup via child elements with data-page
  • Event-driven architecture
  • Easy to integrate

ArsRelationalNode

Reusable DOM node card for graph-based UIs that need browser-native interaction instead of canvas-drawn text.

import { ArsRelationalNode } from "ars-web-components";

const node = new ArsRelationalNode();
node.data = {
  id: "event_alpha",
  title: "Event Alpha",
  subtitle: "is a: event",
  properties: {
    start_date: "2026-03-11",
    owner: "andre",
  },
};
node.setSelected(true);

This component is intended for projected overlays in tools like Nexus or Brainiac Engine where the spatial runtime owns positioning and zoom while the browser owns the card UI.

Mixins

ARS Web Components includes a collection of reusable behavior classes. Each mixin is a concrete custom element class that can be used either as a standalone wrapper element or as the base class for your own element.

Register the mixin tags before using them. The easiest way is to call the central registration helper once at application startup:

import { registerArsWebComponents } from "ars-web-components";
registerArsWebComponents();

If you only need a specific mixin, import the class and register it explicitly:

import { DraggableMixin } from "ars-web-components";

if (!customElements.get("draggable-mixin")) {
  customElements.define("draggable-mixin", DraggableMixin);
}

Using a mixin as a wrapper element

<pressed-effect-mixin>
  <button>Press me</button>
</pressed-effect-mixin>

Using a mixin as a base class

import { PressedEffectMixin } from "ars-web-components";

class MyButton extends PressedEffectMixin {
  constructor() {
    super();
    // Your component logic
  }
}

customElements.define("my-button", MyButton);

PressedEffect Mixin

Adds pressed animation effects to components with solid background colors.

<pressed-effect-mixin>
  <button>Press me</button>
</pressed-effect-mixin>

Features:

  • Automatic color detection from background
  • Smooth pressed animation effects
  • Works with solid background colors
  • Touch and mouse support

Demo: http://localhost:8080/demos/mixins/pressed-effect-mixin/

Localized Mixin

Provides localization capabilities for components with dynamic language switching.

<localized-mixin id="greeting" locale="en">
  <div>Hello World</div>
</localized-mixin>
import { LocalizedMixin } from "ars-web-components";

class LocalizedComponent extends LocalizedMixin {
  constructor() {
    super();
    this.addTranslations("en", { greeting: "Hello World" });
    this.addTranslations("es", { greeting: "Hola Mundo" });
    this.addTranslations("fr", { greeting: "Bonjour le Monde" });
    this.setLocale("en");
  }
}

customElements.define("localized-component", LocalizedComponent);

Features:

  • Dynamic language switching
  • Text localization support
  • Event-driven updates
  • Mock localization system for testing

Demo: http://localhost:8080/demos/mixins/localized-mixin/

RemoteCall Mixins

Enables inter-component communication through DOM events and component IDs.

<remote-call-caller-mixin receiver="my-receiver" method="greet" args='["World"]'>
  <button>Send greeting</button>
</remote-call-caller-mixin>

<remote-call-receiver-mixin id="my-receiver" allow="greet">
  <greeter-element></greeter-element>
</remote-call-receiver-mixin>
class GreeterElement extends HTMLElement {
  greet(name) {
    console.log(`Hello ${name}`);
  }
}
customElements.define("greeter-element", GreeterElement);

Important: Receiver elements must have a unique id attribute, and the wrapped target must expose public methods.

Features:

  • Component ID-based targeting
  • Method call with parameters
  • Error handling and validation
  • Support for multiple receiver instances

Demo: http://localhost:8080/demos/mixins/remote-call-mixin/

ShowIfPropertyTrue Mixin

Conditionally shows/hides the first child element based on a property, data attribute, or regular attribute value.

<show-if-property-true-mixin show-if-property="isVisible">
  <div class="bar">isVisible Bar</div>
</show-if-property-true-mixin>
import { ShowIfPropertyTrueMixin } from "ars-web-components";

// Register once
if (!customElements.get("show-if-property-true-mixin")) {
  customElements.define("show-if-property-true-mixin", ShowIfPropertyTrueMixin);
}

// Toggle visibility by setting the property on the wrapped element
const mixin = document.querySelector("show-if-property-true-mixin");
const target = mixin.firstElementChild;
target.isVisible = true;  // shows the element
target.isVisible = false; // hides the element

Add the keep-space-when-hidden attribute to keep the element's space in the layout when hidden (uses visibility: hidden instead of display: none).

<show-if-property-true-mixin show-if-property="isVisible" keep-space-when-hidden>
  <div class="bar">isVisible Bar</div>
</show-if-property-true-mixin>

Demo: http://localhost:8080/demos/mixins/show-if-property-true-mixin/

Swipeable Mixin

Adds swipe gesture support to components.

<swipeable-mixin min-swipe-distance="30" max-swipe-time="800">
  <div>Swipe me</div>
</swipeable-mixin>
import { SwipeableMixin } from "ars-web-components";

class SwipeableComponent extends SwipeableMixin {
  constructor() {
    super();
    this.onSwipeLeft = () => console.log("Swiped left!");
    this.onSwipeRight = () => console.log("Swiped right!");
  }
}

customElements.define("swipeable-component", SwipeableComponent);

Features:

  • Swipe detection with customizable distance and time thresholds
  • Direction detection (left, right, up, down)
  • Configurable via min-swipe-distance and max-swipe-time attributes
  • Works seamlessly with other mixins using PointerCoordinator
  • Order-independent: Can be nested in any order with other gesture mixins

Demo: http://localhost:8080/demos/mixins/swipeable-mixin/

Draggable Mixin

Adds drag gesture detection to components with customizable thresholds and real-time feedback.

<draggable-mixin drag-threshold="10">
  <div>Drag me</div>
</draggable-mixin>
import { DraggableMixin } from "ars-web-components";

class DraggableComponent extends DraggableMixin {
  constructor() {
    super();
    this.addEventListener('dragstart', (e) => console.log('Drag started:', e.detail));
    this.addEventListener('dragmove', (e) => console.log('Dragging:', e.detail));
    this.addEventListener('dragend', (e) => console.log('Drag ended:', e.detail));
  }
}

customElements.define("draggable-component", DraggableComponent);

Features:

  • Drag start, move, and end events with detailed coordinate data
  • Direction detection (left, right, up, down) with distance tracking
  • Configurable drag threshold via drag-threshold attribute
  • Real-time drag feedback with dragmove events
  • Works seamlessly with other mixins using PointerCoordinator
  • Order-independent: Can be nested in any order with other gesture mixins

Demo: http://localhost:8080/demos/mixins/draggable-mixin/

Roll Mixin

Adds roll animation effects to components.

<roll-mixin>
  <div>Roll me</div>
</roll-mixin>
import { RollMixin } from "ars-web-components";

class RollableComponent extends RollMixin {
  constructor() {
    super();
    this.onRollStart = () => console.log("Roll started!");
    this.onRollEnd = () => console.log("Roll ended!");
  }
}

customElements.define("rollable-component", RollableComponent);

Demo: http://localhost:8080/demos/mixins/roll-mixin/

Mixin Coordination

ARS Web Components includes a sophisticated coordination system that allows multiple gesture mixins to work together seamlessly on the same element.

Pointer Coordination

Gesture mixins in this package share an internal PointerCoordinator utility to manage pointer capture and redispatching. That coordination is what allows drag and swipe behaviors to coexist on the same interaction surface without fighting over the same pointer stream.

Features:

  • Prevents conflicts when multiple mixins try to capture the same pointer
  • Smart scroll prevention that only activates during active gestures
  • Event redispatching system to prevent infinite loops
  • Early gesture detection for responsive touch interactions
  • Order-independent coordination: Works regardless of mixin nesting order

Using Multiple Mixins Together

You can combine multiple gesture mixins on the same element in any order:

<!-- DraggableMixin as parent, SwipeableMixin as child -->
<draggable-mixin drag-threshold="10">
  <swipeable-mixin min-swipe-distance="30" max-swipe-time="800">
    <div>Drag for movement, swipe for quick actions</div>
  </swipeable-mixin>
</draggable-mixin>

<!-- SwipeableMixin as parent, DraggableMixin as child -->
<swipeable-mixin min-swipe-distance="30" max-swipe-time="800">
  <draggable-mixin drag-threshold="10">
    <div>Swipe for quick actions, drag for movement</div>
  </draggable-mixin>
</swipeable-mixin>

In both examples:

  • Dragging will trigger drag events
  • Quick swipes will trigger swipe events
  • Both mixins coordinate through PointerCoordinator
  • Scroll prevention only activates when gestures are detected
  • Order-independent: Works regardless of which mixin is parent/child

Development

Quick Start

cd ars-web-components
npm install
npm run build   # Compile TypeScript → dist/
npm test        # Run all 785 tests
npm start       # Start dev server on port 8080

Scripts

| Script | Description | |---|---| | npm run build | Compile TypeScript to dist/ via tsc | | npm test | Run all tests (Vitest, single run) | | npm run test:watch | Run tests in watch mode | | npm run test:coverage | Run tests with coverage report | | npm run dev | Start the Vite dev server for live demo development | | npm start | Start Express dev server on port 8080 | | npm stop | Stop the dev server |

Experimenting with Components and Mixins

Once the server is running, you can access:

  • Main Demo Gallery: http://localhost:8080/
  • Individual Components:
    • form-primitives (button + toggle): http://localhost:8080/demos/components/form-primitives/
    • ars-input: http://localhost:8080/demos/components/ars-input/
    • ars-color-select: http://localhost:8080/demos/components/ars-color-select/
    • ars-toast: http://localhost:8080/demos/components/ars-toast/
    • ars-tabs: http://localhost:8080/demos/components/ars-tabs/
    • ars-select: http://localhost:8080/demos/components/ars-select/
    • ars-table: http://localhost:8080/demos/components/ars-table/
    • ars-info-tile: http://localhost:8080/demos/components/ars-info-tile/
    • ars-calendar: http://localhost:8080/demos/components/ars-calendar/
    • ars-dialog: http://localhost:8080/demos/components/ars-dialog/
    • ars-page: http://localhost:8080/demos/components/ars-page/
    • ars-data-roller: http://localhost:8080/demos/components/ars-data-roller/
    • ars-line-chart: http://localhost:8080/demos/components/ars-line-chart/
    • ars-candlestick-chart: http://localhost:8080/demos/components/ars-candlestick-chart/
  • Individual Mixins:
    • pressed-effect: http://localhost:8080/demos/mixins/pressed-effect-mixin/
    • localized: http://localhost:8080/demos/mixins/localized-mixin/
    • remote-call: http://localhost:8080/demos/mixins/remote-call-mixin/
    • swipeable: http://localhost:8080/demos/mixins/swipeable-mixin/
    • draggable: http://localhost:8080/demos/mixins/draggable-mixin/
    • show-if-property-true: http://localhost:8080/demos/mixins/show-if-property-true-mixin/
    • roll: http://localhost:8080/demos/mixins/roll-mixin/

Co-development Setup

For projects that need to develop alongside ars-web-components, you can set up symlinks:

# In your project's node_modules
ln -s ../../../../ars-web-components ars-web-components-dev

Available Exports

Check src/index.ts for all available imports:

// Components
export { ArsButton } from "./components/ars-button/ars-button.js";
export { ArsCalendar } from "./components/ars-calendar/ars-calendar.js";
export { ArsCandlestickChart } from "./components/ars-candlestick-chart/ars-candlestick-chart.js";
export { ArsColorSelect } from "./components/ars-color-select/ars-color-select.js";
export { ArsDataRoller } from "./components/ars-data-roller/ars-data-roller.js";
export { ArsDialog } from "./components/ars-dialog/ars-dialog.js";
export { ArsInfoTile } from "./components/ars-info-tile/ars-info-tile.js";
export { ArsInput } from "./components/ars-input/ars-input.js";
export { ArsLineChart } from "./components/ars-line-chart/ars-line-chart.js";
export { ArsPage } from "./components/ars-page/ars-page.js";
export { ArsPageController } from "./components/ars-page/ars-page-controller.js";
export { ArsSelect } from "./components/ars-select/ars-select.js";
export { ArsTable } from "./components/ars-table/ars-table.js";
export { ArsTabs, ArsTabPanel } from "./components/ars-tabs/ars-tabs.js";
export { ArsToast } from "./components/ars-toast/ars-toast.js";
export { ArsToggle } from "./components/ars-toggle/ars-toggle.js";
export { ChartBase } from "./components/chart-base/chart-base.js";
export { ChartGPUContext } from "./components/chart-base/gpu/chart-gpu-context.js";
export { WebComponentBase } from "./components/web-component-base/web-component-base.js";

// Design System
export { getArsWebComponentsDefaultAdapter, initializeArsWebComponents } from "./design-system.js";

// Registration
export { registerArsWebComponents } from "./register.js";

// Mixins
export { DraggableMixin } from "./mixins/draggable-mixin/draggable-mixin.js";
export { LocalizedMixin } from "./mixins/localized-mixin/localized-mixin.js";
export { PressedEffectMixin } from "./mixins/pressed-effect-mixin/pressed-effect-mixin.js";
export { RemoteCallCallerMixin } from "./mixins/remote-call-mixin/remote-call-caller-mixin.js";
export { RemoteCallReceiverMixin } from "./mixins/remote-call-mixin/remote-call-receiver-mixin.js";
export { RollMixin } from "./mixins/roll-mixin/roll-mixin.js";
export { ShowIfPropertyTrueMixin } from "./mixins/show-if-property-true-mixin/show-if-property-true-mixin.js";
export { SwipeableMixin } from "./mixins/swipeable-mixin/swipeable-mixin.js";

Requirements

  • WebGPU-capable browser for chart components (Chrome 113+, Safari 17+, Firefox 141+)
  • Modern browser with ES module support for all other components
  • Node.js (for building and testing)
  • arslib dependency (automatically installed)

License

MIT