@manufosela/multi-carousel

@manufosela/multi-carousel

Responsive multi-slide carousel web component with navigation and arrows

Multi Carousel

Responsive carousel with smooth transitions and keyboard support.

Basic Usage

Navigate with arrows, dots, or keyboard (focus then use arrow keys).

Slide 1
Slide 2
Slide 3
Slide 4
Current: Slide 1
<multi-carousel> <div class="slide slide-1">Slide 1</div> <div class="slide slide-2">Slide 2</div> <div class="slide slide-3">Slide 3</div> <div class="slide slide-4">Slide 4</div> </multi-carousel> <script type="module"> import '@manufosela/multi-carousel'; const carousel = document.querySelector('multi-carousel'); carousel.addEventListener('slide-change', (e) => { console.log(`Slide ${e.detail.index + 1} of ${e.detail.total}`); }); </script>

Image Gallery

Using free images from Picsum Photos.

Random image 1 Random image 2 Random image 3 Random image 4
<multi-carousel style="--carousel-height: 300px;"> <img src="https://picsum.photos/seed/demo1/800/300" alt="Image 1"> <img src="https://picsum.photos/seed/demo2/800/300" alt="Image 2"> <img src="https://picsum.photos/seed/demo3/800/300" alt="Image 3"> <img src="https://picsum.photos/seed/demo4/800/300" alt="Image 4"> </multi-carousel>

No Loop

Stops at first/last slide instead of looping.

First
Middle
Last
<multi-carousel no-loop> <div class="slide slide-1">First</div> <div class="slide slide-2">Middle</div> <div class="slide slide-3">Last</div> </multi-carousel>

Autoplay

Auto-advances every 3 seconds.

Auto 1
Auto 2
Auto 3
<multi-carousel autoplay="3000"> <div class="slide slide-1">Auto 1</div> <div class="slide slide-2">Auto 2</div> <div class="slide slide-3">Auto 3</div> </multi-carousel>

Arrows Only

Hide navigation dots.

Arrows
Only
Mode
<multi-carousel hide-nav> <div class="slide slide-1">Arrows</div> <div class="slide slide-2">Only</div> <div class="slide slide-3">Mode</div> </multi-carousel>

Dots Only

Hide arrow buttons.

Dots
Only
Mode
<multi-carousel hide-arrows> <div class="slide slide-1">Dots</div> <div class="slide slide-2">Only</div> <div class="slide slide-3">Mode</div> </multi-carousel>

Custom Styling

Use CSS variables for theming.

Styled 1
Styled 2
Styled 3
<multi-carousel style=" --carousel-height: 200px; --carousel-bg: #1e293b; --carousel-nav-active: #ec4899; --carousel-arrow-bg: rgba(30,41,59,0.8); --carousel-arrow-color: white; "> <div class="slide slide-4">Styled 1</div> <div class="slide slide-1">Styled 2</div> <div class="slide slide-2">Styled 3</div> </multi-carousel>

Synced Carousels

Multiple carousels that stay in sync.

Master 1
Master 2
Master 3
Synced 1
Synced 2
Synced 3
<multi-carousel id="syncMaster" master style="--carousel-height: 200px;"> <div class="slide slide-1">Master 1</div> <div class="slide slide-2">Master 2</div> <div class="slide slide-3">Master 3</div> </multi-carousel> <multi-carousel master-id="syncMaster" style="--carousel-height: 150px;"> <div class="slide slide-3">Synced 1</div> <div class="slide slide-1">Synced 2</div> <div class="slide slide-2">Synced 3</div> </multi-carousel>
Demo code (CodePen-ready HTML, CSS, JS)
HTML (html)
<h1>Multi Carousel</h1>
<p class="subtitle">Responsive carousel with smooth transitions and keyboard support.</p>
<div class="demo-links">
  <a href="https://manufosela.dev/ui-components/">← Back to components</a>
  <a href="https://github.com/manufosela/ui-components/tree/main/packages/multi-carousel" target="_blank" rel="noopener">GitHub Repo</a>
  <a href="playground.html">Playground</a>
  <a href="https://www.npmjs.com/package/@manufosela/multi-carousel" target="_blank" rel="noopener">npm</a>
</div>
<div class="demo-theme-toggle">
  <theme-toggle theme="dark"></theme-toggle>
</div>
<div class="demo-section">
    <h2>Basic Usage</h2>
    <p>Navigate with arrows, dots, or keyboard (focus then use arrow keys).</p>
    <multi-carousel id="basic">
      <div class="slide slide-1">Slide 1</div>
      <div class="slide slide-2">Slide 2</div>
      <div class="slide slide-3">Slide 3</div>
      <div class="slide slide-4">Slide 4</div>
    </multi-carousel>
    <div class="output" id="basicOutput">Current: Slide 1</div>
    <div class="code-block">&lt;multi-carousel&gt;
  &lt;div class="slide slide-1"&gt;Slide 1&lt;/div&gt;
  &lt;div class="slide slide-2"&gt;Slide 2&lt;/div&gt;
  &lt;div class="slide slide-3"&gt;Slide 3&lt;/div&gt;
  &lt;div class="slide slide-4"&gt;Slide 4&lt;/div&gt;
&lt;/multi-carousel&gt;

&lt;script type="module"&gt;
  import '@manufosela/multi-carousel';

  const carousel = document.querySelector('multi-carousel');
  carousel.addEventListener('slide-change', (e) =&gt; {
    console.log(`Slide ${e.detail.index + 1} of ${e.detail.total}`);
  });
&lt;/script&gt;</div>
      
  </div>

  <div class="demo-section">
    <h2>Image Gallery</h2>
    <p>Using free images from Picsum Photos.</p>
    <multi-carousel style="--carousel-height: 300px;">
      <img src="https://picsum.photos/seed/demo1/800/300" alt="Random image 1" style="width: 100%; height: 100%; object-fit: cover;">
      <img src="https://picsum.photos/seed/demo2/800/300" alt="Random image 2" style="width: 100%; height: 100%; object-fit: cover;">
      <img src="https://picsum.photos/seed/demo3/800/300" alt="Random image 3" style="width: 100%; height: 100%; object-fit: cover;">
      <img src="https://picsum.photos/seed/demo4/800/300" alt="Random image 4" style="width: 100%; height: 100%; object-fit: cover;">
    </multi-carousel>
    <div class="code-block">&lt;multi-carousel style="--carousel-height: 300px;"&gt;
  &lt;img src="https://picsum.photos/seed/demo1/800/300" alt="Image 1"&gt;
  &lt;img src="https://picsum.photos/seed/demo2/800/300" alt="Image 2"&gt;
  &lt;img src="https://picsum.photos/seed/demo3/800/300" alt="Image 3"&gt;
  &lt;img src="https://picsum.photos/seed/demo4/800/300" alt="Image 4"&gt;
&lt;/multi-carousel&gt;</div>
  </div>

  <div class="demo-section">
    <h2>No Loop</h2>
    <p>Stops at first/last slide instead of looping.</p>
    <multi-carousel no-loop>
      <div class="slide slide-1">First</div>
      <div class="slide slide-2">Middle</div>
      <div class="slide slide-3">Last</div>
    </multi-carousel>
    <div class="code-block">&lt;multi-carousel no-loop&gt;
  &lt;div class="slide slide-1"&gt;First&lt;/div&gt;
  &lt;div class="slide slide-2"&gt;Middle&lt;/div&gt;
  &lt;div class="slide slide-3"&gt;Last&lt;/div&gt;
&lt;/multi-carousel&gt;</div>
  </div>

  <div class="demo-section">
    <h2>Autoplay</h2>
    <p>Auto-advances every 3 seconds.</p>
    <multi-carousel autoplay="3000">
      <div class="slide slide-1">Auto 1</div>
      <div class="slide slide-2">Auto 2</div>
      <div class="slide slide-3">Auto 3</div>
    </multi-carousel>
    <div class="code-block">&lt;multi-carousel autoplay="3000"&gt;
  &lt;div class="slide slide-1"&gt;Auto 1&lt;/div&gt;
  &lt;div class="slide slide-2"&gt;Auto 2&lt;/div&gt;
  &lt;div class="slide slide-3"&gt;Auto 3&lt;/div&gt;
&lt;/multi-carousel&gt;</div>
  </div>

  <div class="demo-section">
    <h2>Arrows Only</h2>
    <p>Hide navigation dots.</p>
    <multi-carousel hide-nav>
      <div class="slide slide-1">Arrows</div>
      <div class="slide slide-2">Only</div>
      <div class="slide slide-3">Mode</div>
    </multi-carousel>
    <div class="code-block">&lt;multi-carousel hide-nav&gt;
  &lt;div class="slide slide-1"&gt;Arrows&lt;/div&gt;
  &lt;div class="slide slide-2"&gt;Only&lt;/div&gt;
  &lt;div class="slide slide-3"&gt;Mode&lt;/div&gt;
&lt;/multi-carousel&gt;</div>
  </div>

  <div class="demo-section">
    <h2>Dots Only</h2>
    <p>Hide arrow buttons.</p>
    <multi-carousel hide-arrows>
      <div class="slide slide-1">Dots</div>
      <div class="slide slide-2">Only</div>
      <div class="slide slide-3">Mode</div>
    </multi-carousel>
    <div class="code-block">&lt;multi-carousel hide-arrows&gt;
  &lt;div class="slide slide-1"&gt;Dots&lt;/div&gt;
  &lt;div class="slide slide-2"&gt;Only&lt;/div&gt;
  &lt;div class="slide slide-3"&gt;Mode&lt;/div&gt;
&lt;/multi-carousel&gt;</div>
  </div>

  <div class="demo-section">
    <h2>Custom Styling</h2>
    <p>Use CSS variables for theming.</p>
    <multi-carousel style="
      --carousel-height: 200px;
      --carousel-bg: #1e293b;
      --carousel-nav-active: #ec4899;
      --carousel-arrow-bg: rgba(30,41,59,0.8);
      --carousel-arrow-color: white;
    ">
      <div class="slide slide-4">Styled 1</div>
      <div class="slide slide-1">Styled 2</div>
      <div class="slide slide-2">Styled 3</div>
    </multi-carousel>
    <div class="code-block">&lt;multi-carousel style="
  --carousel-height: 200px;
  --carousel-bg: #1e293b;
  --carousel-nav-active: #ec4899;
  --carousel-arrow-bg: rgba(30,41,59,0.8);
  --carousel-arrow-color: white;
"&gt;
  &lt;div class="slide slide-4"&gt;Styled 1&lt;/div&gt;
  &lt;div class="slide slide-1"&gt;Styled 2&lt;/div&gt;
  &lt;div class="slide slide-2"&gt;Styled 3&lt;/div&gt;
&lt;/multi-carousel&gt;</div>
  </div>

  <div class="demo-section">
    <h2>Synced Carousels</h2>
    <p>Multiple carousels that stay in sync.</p>
    <multi-carousel id="syncMaster" master style="--carousel-height: 200px;">
      <div class="slide slide-1">Master 1</div>
      <div class="slide slide-2">Master 2</div>
      <div class="slide slide-3">Master 3</div>
    </multi-carousel>
    <multi-carousel master-id="syncMaster" style="--carousel-height: 150px; margin-top: 1rem;">
      <div class="slide slide-3">Synced 1</div>
      <div class="slide slide-1">Synced 2</div>
      <div class="slide slide-2">Synced 3</div>
    </multi-carousel>
    <div class="code-block">&lt;multi-carousel id="syncMaster" master style="--carousel-height: 200px;"&gt;
  &lt;div class="slide slide-1"&gt;Master 1&lt;/div&gt;
  &lt;div class="slide slide-2"&gt;Master 2&lt;/div&gt;
  &lt;div class="slide slide-3"&gt;Master 3&lt;/div&gt;
&lt;/multi-carousel&gt;

&lt;multi-carousel master-id="syncMaster" style="--carousel-height: 150px;"&gt;
  &lt;div class="slide slide-3"&gt;Synced 1&lt;/div&gt;
  &lt;div class="slide slide-1"&gt;Synced 2&lt;/div&gt;
  &lt;div class="slide slide-2"&gt;Synced 3&lt;/div&gt;
&lt;/multi-carousel&gt;</div>
  </div>
CSS (css)
:root {
  --bg: #0c0f14;
  --bg-elevated: #141923;
  --bg-panel: #171d28;
  --border: #262f3f;
  --text: #f4f6fb;
  --text-muted: #a7b0c2;
  --text-dim: #7d879b;
  --accent: #ff8a3d;
  --accent-strong: #ff6a00;
  --accent-soft: rgba(255, 138, 61, 0.16);
  --shadow: 0 20px 50px rgba(5, 8, 14, 0.45);
  --radius-lg: 22px;
  --radius-md: 14px;
  --radius-sm: 10px;
  --max-width: 1160px;
}

h1 { color: #1d1d1f; }
    .demo-section {
      background: white;
      padding: 2rem;
      border-radius: 12px;
      margin-bottom: 2rem;
      box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    }
    h2 { margin-top: 0; color: #1d1d1f; }
    p { color: #86868b; line-height: 1.6; }
    a { color: #3b82f6; }
    .code-block {
      background: #1d1d1f;
      color: #f5f5f7;
      padding: 1rem;
      border-radius: 8px;
      font-family: monospace;
      font-size: 0.8rem;
      margin-top: 1rem;
      overflow: auto;
      max-height: 300px;
      white-space: pre;
    }
    .output {
      margin-top: 1rem;
      padding: 1rem;
      background: #f5f5f7;
      border-radius: 8px;
      font-family: monospace;
    }
    .slide {
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 2rem;
      font-weight: bold;
      color: white;
      text-shadow: 0 2px 4px rgba(0,0,0,0.2);
    }
    .slide-1 { background: linear-gradient(135deg, #3b82f6, #8b5cf6); }
    .slide-2 { background: linear-gradient(135deg, #22c55e, #14b8a6); }
    .slide-3 { background: linear-gradient(135deg, #f59e0b, #ef4444); }
    .slide-4 { background: linear-gradient(135deg, #ec4899, #8b5cf6); }
    multi-carousel {
      --carousel-height: 250px;
    }
  
    footer {
      text-align: center;
      margin-top: 3rem;
      padding-top: 2rem;
      border-top: 1px solid #d2d2d7;
      color: #86868b;
      font-size: 0.9rem;
    }
    footer a { color: #1d1d1f; text-decoration: none; }
    footer a:hover { text-decoration: underline; }
  


@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&display=swap');

:root {
  --bg: #f5f5f7;
  --bg-2: #ffffff;
  --bg-spot-1: #f8e9d0;
  --bg-spot-2: #e8eef8;
  --card: #ffffff;
  --text: #1d1d1f;
  --muted: #6b7280;
  --line: #e5e7eb;
  --accent: #ffb000;
  --accent-2: #00a7d6;
  --accent-soft: rgba(255, 176, 0, 0.18);
  --surface-1: #f3f4f6;
  --surface-2: #eef2f7;
  --code-bg: #111827;
  --code-text: #f9fafb;
  --panel-bg: rgba(255, 255, 255, 0.85);
  --overlay-bg: rgba(255, 255, 255, 0.98);
}

:root.dark {
  --bg: #0f1117;
  --bg-2: #151a26;
  --bg-spot-1: #1a2136;
  --bg-spot-2: #1d1b34;
  --card: #1c2233;
  --text: #f3f6ff;
  --muted: #b8c0d9;
  --line: #2b3247;
  --accent: #ffb000;
  --accent-2: #00d0ff;
  --accent-soft: rgba(255, 176, 0, 0.25);
  --surface-1: #0b0f1a;
  --surface-2: #263046;
  --code-bg: #0b0f1a;
  --code-text: #d6d9e6;
  --panel-bg: rgba(28, 34, 51, 0.8);
  --overlay-bg: rgba(15, 17, 23, 0.98);
}

* {
  box-sizing: border-box;
}

a {
  color: var(--accent);
}

h1 {
  color: var(--accent);
}

.demo-links {
  margin-top: 12px;
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
}

.demo-links a {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 12px;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.85rem;
  transition: border-color 0.2s ease, color 0.2s ease;
}

.demo-links a:hover {
  color: var(--text);
  border-color: var(--accent-2);
}

.demo-theme-toggle {
  margin-top: 12px;
  display: flex;
  justify-content: center;
}

header {
  border-bottom: 1px solid var(--line);
}

.demo-card,
.section,
.demo-section,
.panel,
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  color: var(--text);
  box-shadow: 0 18px 36px rgba(6, 10, 24, 0.45);
}

.demo-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.demo-card .code-block {
  margin-top: auto;
}

.demo-grid,
.grid {
  align-items: stretch;
}

.demo-card h2,
.demo-card h3,
.section h2,
.demo-section h2,
.panel-header {
  color: var(--text);
}

.label,
.stat-label,
.category-title,
.subtitle,
.hint,
.note {
  color: var(--muted);
}

.info-item,
.capability,
.preference,
.option-group,
.output,
.current-url,
.event-log,
.result-card,
.log,
.stat {
  background: var(--surface-1);
  border: 1px solid var(--line);
  color: var(--text);
}

.info-item .label,
.capability .name {
  color: var(--muted);
}

.panel-header,
.options,
.topbar,
.top-links {
  background: var(--panel-bg);
  border-bottom: 1px solid var(--line);
  color: var(--text);
}

.subtitle,
.hint,
.note,
.demo-card p,
.section p,
.demo-section p {
  color: var(--muted);
}

.code-block,
pre,
code {
  background: var(--code-bg);
  color: var(--code-text);
  border-radius: 8px;
}

.value-display,
.output,
.result,
.demo-output {
  background: var(--surface-1);
  border: 1px solid var(--line);
  color: var(--text);
}

button {
  background: linear-gradient(120deg, var(--accent), #ff6a00);
  color: #111;
  border: none;
}

button:hover {
  filter: brightness(1.05);
}

input,
select,
textarea {
  background: var(--surface-1);
  color: var(--text);
  border: 1px solid var(--line);
}

footer {
  color: var(--muted);
}

footer a {
  color: var(--text);
}

arc-slider {
  --arc-slider-text-color: var(--text);
  --arc-slider-value-bg: var(--surface-1);
  --arc-slider-value-border: var(--line);
  --arc-slider-value-shadow: 0 6px 16px rgba(0, 0, 0, 0.35);
}

rich-select {
  --caller-background: var(--card);
  --caller-color: var(--text);
  --caller-border: 1px solid var(--line);
  --caller-hover-background: var(--surface-2);
  --caller-hover-color: var(--text);
  --caller-hover-border-color: var(--line);
  --caller-focus-border-color: var(--accent-2);
  --caller-focus-shadow: 0 0 0 3px rgba(0, 208, 255, 0.25);
  --caller-disabled-background: var(--surface-1);
  --caller-disabled-color: #6b7280;
  --caller-disabled-border-color: var(--line);
  --arrow-color: var(--muted);
  --selectOptions-background: var(--card);
  --selectOptions-border: 1px solid var(--line);
  --selectOptions-shadow: 0 10px 22px rgba(0, 0, 0, 0.45);
  --input-background: var(--surface-1);
  --input-border: 1px solid var(--line);
  --input-color: var(--text);
  --input-placeholder-color: #6b7280;
  --option-color: var(--text);
  --option-hover-background: var(--surface-2);
  --option-hover-color: var(--text);
  --option-active-background: var(--accent);
  --option-active-color: #111;
  --option-selected-background: var(--accent-soft);
  --option-selected-color: var(--text);
  --option-disabled-background: var(--surface-1);
  --option-disabled-color: #6b7280;
}

multi-select {
  --multi-select-bg: var(--card);
  --multi-select-border-color: var(--line);
  --multi-select-border-hover: var(--line);
  --multi-select-border-focus: var(--accent-2);
  --multi-select-text-color: var(--text);
  --multi-select-placeholder-color: #6b7280;
  --multi-select-arrow-color: var(--muted);
  --multi-select-dropdown-bg: var(--card);
  --multi-select-shadow: 0 10px 22px rgba(0, 0, 0, 0.45);
  --multi-select-option-hover-bg: var(--surface-2);
  --multi-select-option-selected-bg: var(--accent-soft);
}

tab-nav {
  --tab-bg: var(--card);
  --tab-border: var(--line);
  --tab-text: var(--muted);
  --tab-active-text: var(--text);
  --tab-hover-bg: var(--surface-2);
  --tab-active-border: var(--accent);
  --tab-disabled: #9ca3af;
}

slider-underline {
  --slider-track: var(--surface-2);
  --slider-fill: var(--accent);
  --slider-thumb: var(--accent);
  --slider-label-color: var(--text);
  --slider-tick-color: #9ca3af;
  --slider-tick-value-color: var(--muted);
}

header-nav {
  --header-bg: var(--card);
  --header-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
  --header-link-color: var(--text);
  --header-link-hover: var(--accent);
  --header-mobile-hover-bg: var(--surface-2);
}

calendar-inline {
  --calendar-bg: var(--card);
  --calendar-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
  --calendar-text: var(--text);
  --calendar-accent: var(--accent);
  --calendar-today: var(--accent-soft);
  --calendar-selected: var(--accent);
  --calendar-hover-bg: var(--surface-2);
  --calendar-muted: var(--muted);
  --calendar-muted-strong: #9ca3af;
  --calendar-other-month: #9ca3af;
  --calendar-disabled: #cbd5e1;
  --calendar-holiday: #ef4444;
  --calendar-holiday-selected: #111;
}

marked-calendar {
  --calendar-bg: var(--card);
  --calendar-border: var(--line);
  --calendar-title: var(--text);
  --calendar-muted: var(--muted);
  --calendar-surface: var(--surface-1);
  --calendar-accent: var(--accent);
  --calendar-accent-hover: #ff7a1a;
  --calendar-border-strong: var(--line);
  --calendar-contrast: #111;
  --calendar-nav-bg: var(--surface-1);
  --calendar-nav-hover: var(--surface-2);
}

radar-chart {
  --radar-bg: var(--card);
  --radar-grid-color: var(--line);
  --radar-axis-color: #94a3b8;
  --radar-label-color: var(--muted);
}

multi-carousel {
  --carousel-bg: var(--card);
  --carousel-arrow-bg: var(--surface-1);
  --carousel-arrow-color: var(--text);
  --carousel-arrow-hover-bg: var(--surface-2);
  --carousel-arrow-hover-color: var(--text);
  --carousel-nav-bg: var(--surface-1);
  --carousel-nav-color: var(--muted);
  --carousel-nav-hover: #9ca3af;
  --carousel-nav-active: var(--accent);
  --carousel-focus-color: var(--accent-2);
}

nav-list {
  --nav-list-bg: var(--card);
  --nav-list-border-color: var(--line);
  --nav-list-selected-border-color: var(--accent);
  --nav-list-selected-bg: var(--surface-2);
  --nav-list-hover-bg: var(--surface-2);
  --nav-list-selected-color: var(--text);
}

theme-toggle {
  --theme-toggle-bg: var(--card);
  --theme-toggle-icon-color: var(--muted);
  --theme-toggle-hover-bg: var(--surface-2);
  --theme-toggle-active-bg: var(--surface-1);
  --theme-toggle-active-color: var(--text);
  --theme-toggle-dark-bg: var(--card);
  --theme-toggle-dark-border: var(--line);
  --theme-toggle-dark-icon-color: var(--muted);
  --theme-toggle-dark-active-bg: var(--surface-1);
  --theme-toggle-dark-active-color: var(--text);
  --theme-toggle-dark-hover-bg: var(--surface-2);
}

qr-code {
  --qr-fg: #0f1117;
  --qr-bg: #f3f6ff;
}

click-clock {
  --clock-color: var(--text);
  --clock-bg: var(--card);
  --clock-muted-color: var(--muted);
}

historical-line {
  --title-color: var(--text);
  --border-color: var(--line);
  --year-bg: var(--surface-1);
}

circle-steps {
  --steps-muted: var(--muted);
  --steps-text: var(--text);
  --steps-pending: var(--surface-2);
}

rich-inputfile {
  --input-border: var(--line);
  --input-border-focus: var(--accent-2);
  --input-bg: var(--card);
  --input-label-color: var(--text);
  --input-hover-bg: var(--surface-2);
  --input-drag-bg: var(--accent-soft);
  --input-disabled-bg: var(--surface-1);
  --input-success-border: #22c55e;
  --input-success-bg: rgba(34, 197, 94, 0.12);
  --input-icon-color: #94a3b8;
  --input-text-color: var(--muted);
  --input-accent-color: var(--accent-2);
  --input-file-bg: var(--surface-1);
  --input-preview-bg: var(--surface-1);
  --input-file-name-color: var(--text);
  --input-file-size-color: var(--muted);
  --input-error-color: #ef4444;
  --input-hint-color: var(--muted);
}

data-card {
  --data-card-bg: var(--card);
  --data-card-border-color: var(--line);
  --data-card-title-color: var(--text);
  --data-card-desc-color: var(--muted);
  --data-card-info-bg: var(--overlay-bg);
  --data-card-info-close-bg: var(--surface-2);
  --data-card-info-close-color: var(--text);
  --data-card-info-close-hover-bg: var(--surface-1);
  --data-card-info-text: var(--text);
  --data-card-loading-color: var(--muted);
  --data-card-info-trigger-hover: var(--accent);
}

app-modal {
  --app-modal-bg: var(--card);
  --app-modal-body-color: var(--text);
  --app-modal-standalone-bg: rgba(255, 176, 0, 0.35);
  --app-modal-standalone-color: #111;
  --app-modal-standalone-hover-bg: rgba(255, 176, 0, 0.6);
}
JS (js)
document.querySelectorAll('.footer-year').forEach(el => el.textContent = new Date().getFullYear());
  

    import "https://esm.sh/@manufosela/multi-carousel";

    const basic = document.getElementById('basic');
    const output = document.getElementById('basicOutput');

    basic.addEventListener('slide-change', (e) => {
      output.textContent = `Current: Slide ${e.detail.index + 1} of ${e.detail.total}`;
    });
  

  import '../../theme-toggle/src/theme-toggle.js';

  const root = document.documentElement;
  root.classList.add('dark');

  const toggle = document.querySelector('theme-toggle');
  if (toggle) {
    toggle.theme = root.classList.contains('dark') ? 'dark' : 'light';
    toggle.addEventListener('theme-changed', (event) => {
      const theme = event.detail?.theme;
      if (!theme) return;
      root.classList.toggle('dark', theme === 'dark');
    });
  }