Monochrome Edge UI Components

A modern, minimalist UI Components with two distinct themes. Warm theme for content management systems and publishing, Cold theme for SaaS applications and API businesses.

Warm Theme

Warm, content-focused design for CMS and publishing platforms. Features warm gray tones with earthy accents like Wine (#4a3636) and Olive (#7a7d6e).

Cold Theme

Cold, professional design for SaaS and API-driven businesses. Features cool gray tones with emphasis on Cool Gray 600 (#4b5563).

Layout Templates

Doc Layout

Documentation-focused layout with sidebar navigation, search functionality, and content hierarchy.

View Details →

Blog Layout

Blog-focused layout with article listings, author information, and reading progress.

View Details →

Colors CSS

Our color system is built on Pantone colors with semantic variations for different use cases. Features both Warm theme (earth tones) and Cold theme (cool contrasts) with semantic colors for success, warning, error, and info states.

Theme Colors

Base Colors

Semantic Colors

Success #7B9F60
Warning #D4A574
Error #8B3A3A
Info #6B7280
/* Cool Gray Color Scale */
--cool-100: #F7F8F9;
--cool-200: #E5E7EB;
--cool-300: #D1D5DB;
--cool-400: #9CA3AF;
--cool-500: #6B7280;
--cool-600: #4B5563;
--cool-700: #374151;
--cool-800: #1F2937;
--cool-900: #111827;

/* Theme Highlights */
--theme-highlight: #1E3A8A; /* Light: Deep navy blue */
--theme-highlight: #3B82F6; /* Dark: Navy blue */

Dual Theme System

Switch between Warm and Cold themes dynamically with a single CSS file.

Current Theme: -

Variable Preview
Background var(--theme-bg)
Accent var(--theme-accent)
<!-- Load single CSS file with both themes -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui@latest/dist/monochrome.min.css">

<!-- Set initial theme -->
<html data-theme="light" data-theme-variant="warm">

<script>
// Switch theme dynamically
function switchTheme(variant) {
    document.documentElement.setAttribute('data-theme-variant', variant);
}
</script>

<button onclick="switchTheme('warm')">Warm Theme</button>
<button onclick="switchTheme('cold')">Cold Theme</button>

Mono Theme: Warm Only

Use Warm theme exclusively for content-focused sites (blogs, documentation).

Warm Theme Features

Feature Value
Font Size 16px (body)
Color Palette Warm Gray
Border Radius 8px
Best For Blogs, Documentation
<!-- Load main CSS and warm theme only -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui@latest/dist/monochrome.min.css">

<!-- Set warm theme variant -->
<html data-theme="light" data-theme-variant="warm">

<!-- No JavaScript needed - static theme -->

Mono Theme: Cold Only

Use Cold theme exclusively for SaaS and dashboard applications.

Cold Theme Features

Feature Value
Font Size 15px (body)
Color Palette Cool Gray
Border Radius 6px
Best For SaaS, Dashboards
<!-- Load main CSS and cold theme only -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui@latest/dist/monochrome.min.css">

<!-- Set cold theme variant -->
<html data-theme="light" data-theme-variant="cold">

<!-- No JavaScript needed - static theme -->

Using Color Variables

Primary text with theme surface background

Secondary text color

Accent background with contrast text

HTML/CSS

<!-- Import Monochrome Edge CSS -->
<link rel="stylesheet" href="@monochrome-edge/ui/dist/monochrome.min.css">

<!-- Use CSS variables -->
<div style="background: var(--theme-surface); color: var(--theme-text-primary)">
  Content with theme colors
</div>

<style>
.custom-element {
  background: var(--theme-accent);
  color: var(--theme-accent-contrast);
  border: 1px solid var(--theme-border);
}
</style>

React

import '@monochrome-edge/ui/dist/monochrome.min.css';

function MyComponent() {
  return (
    <div style={{
      background: 'var(--theme-surface)',
      color: 'var(--theme-text-primary)',
      padding: '1rem',
      borderRadius: 'var(--border-radius)'
    }}>
      Content with theme colors
    </div>
  );
}

// Or use className with CSS
<div className="my-themed-component">Content</div>

Vue

<template>
  <div :style="themeStyle">
    Content with theme colors
  </div>
</template>

<script setup>
import '@monochrome-edge/ui/dist/monochrome.min.css';

const themeStyle = {
  background: 'var(--theme-surface)',
  color: 'var(--theme-text-primary)',
  padding: '1rem',
  borderRadius: 'var(--border-radius)'
};
</script>

Web Components

class MyComponent extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }

  connectedCallback() {
    this.shadowRoot.innerHTML = \`
      <style>
        :host {
          display: block;
          background: var(--theme-surface);
          color: var(--theme-text-primary);
          padding: 1rem;
          border-radius: var(--border-radius);
        }
      </style>
      <slot></slot>
    \`;
  }
}

Vanilla JavaScript

// Change theme dynamically
document.documentElement.setAttribute('data-theme', 'dark');
document.documentElement.setAttribute('data-theme-variant', 'cold');

// Access CSS variable values
const accentColor = getComputedStyle(document.documentElement)
  .getPropertyValue('--theme-accent');

// Set custom CSS variable
document.documentElement.style.setProperty('--theme-accent', '#new-color');

// Apply to element
const element = document.createElement('div');
element.style.background = 'var(--theme-surface)';
element.style.color = 'var(--theme-text-primary)';

Typography CSS

Clean, readable typography system based on Inter font family with full type scale (h1-h6), body text variants, display text, and semantic text styles (muted, emphasized, small).

Type Scale

Heading 1 - 2.5rem

Heading 2 - 2rem

Heading 3 - 1.5rem

Heading 4 - 1.25rem

Body text - 1rem

Small body text - 0.875rem

Caption text - 0.75rem

HTML/CSS

<!-- Typography is styled by default - no classes needed -->
<h1>Main Heading</h1>
<h2>Subheading</h2>
<p>Body text content</p>
<small>Secondary text</small>

<!-- Optional: Use utility classes for specific styling -->
<p class="text-muted">Muted text</p>
<p class="text-emphasis">Emphasized text</p>

React

import '@monochrome-edge/ui/styles.css';

function MyComponent() {
  return (
    <div>
      <h1>Main Heading</h1>
      <h2>Subheading</h2>
      <p>Body text content</p>
      <small>Secondary text</small>

      {/* Optional utility classes */}
      <p className="text-muted">Muted text</p>
    </div>
  );
}

Vue.js

<template>
  <div>
    <h1>Main Heading</h1>
    <h2>Subheading</h2>
    <p>Body text content</p>
    <small>Secondary text</small>

    <!-- Optional utility classes -->
    <p class="text-muted">Muted text</p>
  </div>
</template>

<script setup>
import '@monochrome-edge/ui/styles.css';
</script>

Web Components

<link rel="stylesheet" href="@monochrome-edge/ui/styles.css">

<my-component>
  <h1>Main Heading</h1>
  <h2>Subheading</h2>
  <p>Body text content</p>
  <small>Secondary text</small>
</my-component>

jQuery

// Add typography elements dynamically
$('<h1>').text('Main Heading').appendTo('#container');
$('<h2>').text('Subheading').appendTo('#container');
$('<p>').text('Body text content').appendTo('#container');
$('<small>').text('Secondary text').appendTo('#container');

// Add utility class if needed
$('<p>').addClass('text-muted').text('Muted text').appendTo('#container');

Paragraph & Text Formatting

This is a regular paragraph with natural line height and comfortable reading width. Paragraphs support bold text, italic text, and hyperlinks for rich text formatting.

Multiple paragraphs are automatically spaced for optimal readability. The typography system ensures consistent vertical rhythm throughout your content.

<div class="blog-content">
    <p>Regular paragraph with <strong>bold</strong>, <em>italic</em>, and <a href="#">link</a>.</p>
</div>

Lists

Unordered List

  • First item with some content
  • Second item with bold text
  • Third item with inline code

Ordered List

  1. Step one of the process
  2. Step two continues here
  3. Step three completes it
<div class="blog-content">
    <ul>
        <li>First item</li>
        <li>Second item</li>
    </ul>

    <ol>
        <li>First step</li>
        <li>Second step</li>
    </ol>
</div>

Inline Code

Use inline code for variable names like const example = true, function names like getUserData(), or file paths like /src/components/Button.tsx.

<div class="blog-content">
    <p>Inline code: <code>const x = 1;</code></p>
</div>

Code Blocks

// JavaScript example
function greet(name) {
    return `Hello, ${name}!`;
}

console.log(greet('World'));
<div class="blog-content">
    <pre><code>// Code block
function example() {
    return true;
}</code></pre>
</div>

Blockquote

This is a blockquote with modern edge styling. It's used for quotations or important notes that need to stand out from the main content.

<div class="blog-content">
    <blockquote>
        <p>Blockquote text</p>
    </blockquote>
</div>

Horizontal Rule

Content above the divider.


Content below the divider.

<div class="blog-content">
    <hr />
</div>

Tables

Feature Description Status
Typography Complete type system ✓ Done
Components UI component library ✓ Done
Themes Dual-theme support ✓ Done
<div class="blog-content">
    <table>
        <thead>
            <tr><th>Header</th></tr>
        </thead>
        <tbody>
            <tr><td>Cell</td></tr>
        </tbody>
    </table>
</div>

Math Equations

Inline Math

The quadratic formula x = \frac{-b \pm \sqrt{b^2-4ac}}{2a} is used to solve quadratic equations.

Display Math (Block)

\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}

Complex Equations

\frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\cdots} } } }

Matrix

\begin{pmatrix} a & b \\ c & d \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix} = \begin{pmatrix} ax + by \\ cx + dy \end{pmatrix}
import { MathRenderer, renderAllMath } from '@monochrome-edge/ui';

// Render a single equation
const equation = new MathRenderer({
  container: '#my-equation',
  displayMode: true
});

// Update equation dynamically
equation.update('E = mc^2');

// Or render all math elements on the page
renderAllMath({
  inlineSelector: '.math-inline',
  displaySelector: '.math-display'
});

// HTML:
// <span class="math-inline">E = mc^2</span>
// <div class="math-display">\int_0^1 x^2 dx</div>

Brand Assets SVG

Logo and brand identity elements for the Monochrome Edge design system.

Logo

Icon System

bold

italic

strikethrough

code

code-block

list-ul

list-ol

checkbox

quote

link

image

table

sun

moon

flame

snowflake

palette

globe

search

menu

close

plus

check

completed

circle

file

folder

file-plus

folder-plus

github

x-social

linkedin

facebook

instagram

youtube

slack

discord

// JavaScript - Using iconLoader
import { iconLoader } from '@src/iconLoader';

// Async loading
const svg = await iconLoader.load('search', { width: 20, height: 20 });
element.innerHTML = svg;

// Sync loading (cached or placeholder)
const svg = iconLoader.loadSync('search', { width: 20, height: 20 });

// Using helper utilities
import { createIcon, setIcon, createIconButton } from '@utils/icon.js';

// Create icon element
const iconEl = await createIcon('search', { width: 20, height: 20 });

// Set icon on existing element
await setIcon(buttonElement, 'search', { width: 16, height: 16 });

// Create icon button
const btn = await createIconButton('close', {
  width: 16,
  height: 16,
  title: 'Close',
  onClick: () => console.log('clicked')
});

Landscape Background CSSSVGJS

Background patterns and textures for creating visual depth.

Landscape Patterns

Wave
<!-- Wave Landscape -->
<div class="b-landscape b-landscape-wave"></div>

<!-- Mountain Landscape -->
<div class="b-landscape b-landscape-mountain"></div>

<!-- Forest Landscape -->
<div class="b-landscape b-landscape-forest"></div>

<!-- Desert Landscape -->
<div class="b-landscape b-landscape-desert"></div>
/* Base Landscape */
.b-landscape {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: 320px;
    pointer-events: none;
    z-index: 0;
}

/* Wave - Animated flowing waves */
.b-landscape-wave .wave-layer {
    animation: wave 8s ease-in-out infinite;
}

/* Mountain - Parallax mountain ranges */
.b-landscape-mountain .mountain-layer {
    animation: parallax-mountain 20s ease-in-out infinite;
}

/* Forest - Swaying trees */
.b-landscape-forest .tree {
    animation: tree-sway 4s ease-in-out infinite;
}

/* Desert - Shifting sand dunes */
.b-landscape-desert .dune {
    animation: dune-shift 30s ease-in-out infinite;
}

Table of Contents CSSJS

Navigation components for article content with hover card and collapsible list styles.

Hover Card TOC

<div class="toc-hover-card">
    <div class="toc-card">
        <h4 class="toc-card-title">Contents</h4>
        <ul class="toc-card-list">
            <li class="toc-card-item">
                <a href="#intro" class="toc-card-link">Introduction</a>
            </li>
            <li class="toc-card-item">
                <a href="#start" class="toc-card-link">Getting Started</a>
            </li>
        </ul>
    </div>
</div>

Collapsible List TOC

HTML/CSS

<div class="toc-collapsible is-open">
    <div class="toc-collapsible-header">
        <h4 class="toc-collapsible-title">Table of Contents</h4>
        <span class="toc-collapsible-icon">▼</span>
    </div>
    <div class="toc-collapsible-content">
        <ul class="toc-list">
            <li class="toc-list-item">
                <a href="#intro" class="toc-list-link is-active">Introduction</a>
            </li>
            <li class="toc-list-item">
                <a href="#start" class="toc-list-link">Getting Started</a>
            </li>
        </ul>
    </div>
</div>

<script>
// Toggle collapsible TOC
$('.toc-collapsible-header').on('click', function() {
    $(this).parent().toggleClass('is-open');
});
</script>

React

import { TOC } from '@monochrome-edge/ui/react';

const tocItems = [
  { id: '1', label: 'Introduction', href: '#intro' },
  { id: '2', label: 'Getting Started', href: '#start' },
  { id: '3', label: 'Core Concepts', href: '#concepts' },
  { id: '4', label: 'API Reference', href: '#api' }
];

<TOC
  items={tocItems}
  activeId="1"
  collapsible={true}
  title="Table of Contents"
  onItemClick={(item) => console.log('Clicked:', item)}
/>

Vue.js

<script setup>
import { TOC } from '@monochrome-edge/ui/vue';

const tocItems = [
  { id: '1', label: 'Introduction', href: '#intro' },
  { id: '2', label: 'Getting Started', href: '#start' },
  { id: '3', label: 'Core Concepts', href: '#concepts' },
  { id: '4', label: 'API Reference', href: '#api' }
];

const handleItemClick = (item) => {
  console.log('Clicked:', item);
};
</script>

<template>
  <TOC
    :items="tocItems"
    active-id="1"
    :collapsible="true"
    title="Table of Contents"
    @item-click="handleItemClick"
  />
</template>

Web Components

<mce-toc
  title="Table of Contents"
  collapsible
  active-id="1"
>
  <mce-toc-item id="1" href="#intro">Introduction</mce-toc-item>
  <mce-toc-item id="2" href="#start">Getting Started</mce-toc-item>
  <mce-toc-item id="3" href="#concepts">Core Concepts</mce-toc-item>
  <mce-toc-item id="4" href="#api">API Reference</mce-toc-item>
</mce-toc>

<script>
const toc = document.querySelector('mce-toc');
toc.addEventListener('item-click', (e) => {
  console.log('Clicked:', e.detail);
});
</script>

jQuery

$('#toc').toc({
  items: [
    { id: '1', label: 'Introduction', href: '#intro' },
    { id: '2', label: 'Getting Started', href: '#start' },
    { id: '3', label: 'Core Concepts', href: '#concepts' },
    { id: '4', label: 'API Reference', href: '#api' }
  ],
  activeId: '1',
  collapsible: true,
  title: 'Table of Contents',
  onItemClick: function(item) {
    console.log('Clicked:', item);
  }
});

Graph View CANVAS JS

Visualize relationships between your documents and content. Click nodes to explore connections, hover for detailed metadata, and discover how your information is interconnected.

Interactive Graph

Vanilla JS

import { GraphView } from '@monochrome-edge/ui';

const documents = [
  {
    id: 'doc1',
    title: 'Introduction',
    tags: ['overview', 'getting-started'],
    links: [{ target: 'doc2', type: 'reference' }]
  },
  {
    id: 'doc2',
    title: 'API Reference',
    tags: ['api', 'reference'],
    links: [{ target: 'doc3', type: 'reference' }]
  }
];

const graphView = new MonochromeEdge.GraphView({
  container: '#graph-container',
  documents,
  nodeRadius: 8,
  showLabels: true,
  onNodeClick: (node) => console.log('Clicked:', node.title),
  onNodeHover: (node) => {
    if (node) console.log('Hovering:', node.title);
  }
});

React

import { GraphView } from '@monochrome-edge/react';

function DocumentGraph({ documents }) {
  const handleNodeClick = (node) => {
    console.log('Clicked:', node.title);
  };

  return (
    <GraphView
      documents={documents}
      width={800}
      height={600}
      nodeRadius={8}
      showLabels={true}
      onNodeClick={handleNodeClick}
      onNodeHover={(node) => {
        if (node) console.log('Hovering:', node.title);
      }}
    />
  );
}

Vue

<template>
  <GraphView
    :documents="documents"
    :width="800"
    :height="600"
    :node-radius="8"
    :show-labels="true"
    @node-click="handleNodeClick"
    @node-hover="handleNodeHover"
  />
</template>

<script setup>
import { GraphView } from '@monochrome-edge/vue';

const documents = ref([
  { id: 'doc1', title: 'Introduction', tags: ['overview'] },
  { id: 'doc2', title: 'API Reference', tags: ['api'] }
]);

const handleNodeClick = (node) => {
  console.log('Clicked:', node.title);
};

const handleNodeHover = (node) => {
  if (node) console.log('Hovering:', node.title);
};
</script>

Web Components

<mce-graph-view
  id="graph"
  width="800"
  height="600"
></mce-graph-view>

<script type="module">
  import '@monochrome-edge/web-components';

  const graph = document.getElementById('graph');

  const documents = [
    { id: 'doc1', title: 'Introduction', tags: ['overview'] },
    { id: 'doc2', title: 'API Reference', tags: ['api'] }
  ];

  graph.setDocuments(documents);

  graph.addEventListener('node-click', (e) => {
    console.log('Clicked:', e.detail.title);
  });
</script>

jQuery

$('#graph-container').graphView({
  documents: [
    { id: 'doc1', title: 'Introduction', tags: ['overview'] },
    { id: 'doc2', title: 'API Reference', tags: ['api'] }
  ],
  width: 800,
  height: 600,
  nodeRadius: 8,
  showLabels: true,
  onNodeClick: (node) => {
    console.log('Clicked:', node.title);
  },
  onNodeHover: (node) => {
    if (node) console.log('Hovering:', node.title);
  }
});

Tree View CSS JS

Navigate nested structures intuitively. Expand folders to reveal contents, collapse to simplify your view. Perfect for file systems, documentation, and any hierarchical data.

File System Tree

Project Structure

HTML/CSS

<div class="tree-view">
  <div class="tree-node">
    <div class="tree-node-content">
      <span class="tree-toggle">▶</span>
      <span class="tree-icon">📁</span>
      <span class="tree-label">src</span>
    </div>
    <div class="tree-children">
      <div class="tree-node">
        <div class="tree-node-content">
          <span class="tree-icon">📄</span>
          <span class="tree-label">index.ts</span>
        </div>
      </div>
    </div>
  </div>
</div>

React

import { TreeView } from '@monochrome-edge/ui/react';

const treeData = [
  {
    id: 'src',
    label: 'src',
    icon: '📁',
    children: [
      {
        id: 'components',
        label: 'components',
        icon: '📁',
        children: [
          { id: 'button', label: 'Button.tsx', icon: '📄' },
          { id: 'card', label: 'Card.tsx', icon: '📄' }
        ]
      },
      { id: 'utils', label: 'utils.ts', icon: '📄' }
    ]
  }
];

<TreeView
  data={treeData}
  expandedByDefault={false}
  onNodeClick={(node) => console.log('Clicked:', node.label)}
  onNodeToggle={(node, isExpanded) => {
    console.log('Toggled:', node.label, isExpanded);
  }}
/>

Vue.js

<script setup>
import { TreeView } from '@monochrome-edge/ui/vue';

const treeData = [
  {
    id: 'src',
    label: 'src',
    icon: '📁',
    children: [
      {
        id: 'components',
        label: 'components',
        icon: '📁',
        children: [
          { id: 'button', label: 'Button.tsx', icon: '📄' },
          { id: 'card', label: 'Card.tsx', icon: '📄' }
        ]
      },
      { id: 'utils', label: 'utils.ts', icon: '📄' }
    ]
  }
];

const handleNodeClick = (node) => {
  console.log('Clicked:', node.label);
};

const handleNodeToggle = (node, isExpanded) => {
  console.log('Toggled:', node.label, isExpanded);
};
</script>

<template>
  <TreeView
    :data="treeData"
    :expanded-by-default="false"
    @node-click="handleNodeClick"
    @node-toggle="handleNodeToggle"
  />
</template>

Web Components

<mce-tree-view id="tree"></mce-tree-view>

<script type="module">
const tree = document.getElementById('tree');

const treeData = [
  {
    id: 'src',
    label: 'src',
    icon: '📁',
    children: [
      {
        id: 'components',
        label: 'components',
        icon: '📁',
        children: [
          { id: 'button', label: 'Button.tsx', icon: '📄' },
          { id: 'card', label: 'Card.tsx', icon: '📄' }
        ]
      },
      { id: 'utils', label: 'utils.ts', icon: '📄' }
    ]
  }
];

tree.data = treeData;

tree.addEventListener('node-click', (e) => {
  console.log('Clicked:', e.detail.label);
});

tree.addEventListener('node-toggle', (e) => {
  console.log('Toggled:', e.detail.label, e.detail.isExpanded);
});
</script>

jQuery

$('#tree-container').treeView({
  data: [
    {
      id: 'src',
      label: 'src',
      icon: '📁',
      children: [
        {
          id: 'components',
          label: 'components',
          icon: '📁',
          children: [
            { id: 'button', label: 'Button.tsx', icon: '📄' },
            { id: 'card', label: 'Card.tsx', icon: '📄' }
          ]
        },
        { id: 'utils', label: 'utils.ts', icon: '📄' }
      ]
    }
  ],
  expandedByDefault: false,
  onNodeClick: function(node) {
    console.log('Clicked:', node.label);
  },
  onNodeToggle: function(node, isExpanded) {
    console.log('Toggled:', node.label, isExpanded);
  }
});

// API methods
$('#tree-container').treeView('expandAll');
$('#tree-container').treeView('collapseAll');

Tabs CSSJS

Tab navigation component with multiple styles and orientations.

Tab Variants

Home tab content goes here.

<!-- Default Tabs -->
<div class="tabs">
    <div class="tabs-list">
        <button class="tab active">Home</button>
        <button class="tab">Profile</button>
        <button class="tab">Settings</button>
    </div>
    <div class="tabs-panels">
        <div class="tab-panel active">Content here</div>
    </div>
</div>

<!-- Pills Style -->
<div class="tabs">
    <div class="tabs-list tabs-pills">
        <button class="tab active">Dashboard</button>
        <button class="tab">Analytics</button>
    </div>
</div>

<!-- Boxed Style -->
<div class="tabs">
    <div class="tabs-list tabs-boxed">
        <button class="tab active">Code</button>
        <button class="tab">Preview</button>
    </div>
</div>

React

import { Tabs } from '@monochrome-edge/react';

function MyTabs() {
  const tabs = [
    { id: 'home', label: 'Home', content: <div>Home content</div> },
    { id: 'profile', label: 'Profile', content: <div>Profile content</div> },
    { id: 'settings', label: 'Settings', content: <div>Settings content</div> }
  ];

  const handleChange = (tabId) => {
    console.log('Active tab:', tabId);
  };

  return (
    <Tabs
      tabs={tabs}
      defaultActiveId="home"
      onChange={handleChange}
    />
  );
}

Vue

<template>
  <Tabs
    :tabs="tabs"
    default-active-id="home"
    @change="handleChange"
  />
</template>

<script setup>
import { Tabs } from '@monochrome-edge/vue';

const tabs = [
  { id: 'home', label: 'Home', content: 'Home content' },
  { id: 'profile', label: 'Profile', content: 'Profile content' },
  { id: 'settings', label: 'Settings', content: 'Settings content' }
];

const handleChange = (tabId) => {
  console.log('Active tab:', tabId);
};
</script>

Web Components

<mce-tabs id="tabs">
  <div slot="tab-home" data-label="Home">Home content</div>
  <div slot="tab-profile" data-label="Profile">Profile content</div>
  <div slot="tab-settings" data-label="Settings">Settings content</div>
</mce-tabs>

<script type="module">
  import '@monochrome-edge/web-components';

  const tabs = document.getElementById('tabs');
  tabs.addEventListener('tab-change', (e) => {
    console.log('Active tab:', e.detail.tabId);
  });
</script>

jQuery

$('#tabs-container').tabs({
  defaultActiveId: 'home',
  onChange: (tabId) => {
    console.log('Active tab:', tabId);
  }
});

// HTML structure for jQuery
<div id="tabs-container">
  <div data-tab-id="home" data-tab-label="Home">Home content</div>
  <div data-tab-id="profile" data-tab-label="Profile">Profile content</div>
  <div data-tab-id="settings" data-tab-label="Settings">Settings content</div>
</div>

Progress Bar CSS

Progress indicators for loading states, file uploads, and multi-step processes. Supports linear bars and step-based progress.

Linear Progress

Monochrome (Accent Color)

Downloading... 45%
Processing... 75%

Colored (Semantic Colors)

Success 100%
Warning 60%
Error 30%
Info 85%

Sizes

Extra Small
Small
Medium (Default)
Large
Extra Large

Indeterminate Loading

HTML/CSS

<!-- Basic Progress Bar with data attribute -->
<div class="progress" data-value="45">
  <div class="progress-bar"></div>
</div>

<!-- Striped & Animated -->
<div class="progress" data-value="75">
  <div class="progress-bar progress-striped progress-animated"></div>
</div>

<!-- Colored (Semantic) -->
<div class="progress" data-value="100">
  <div class="progress-bar progress-success"></div>
</div>
<div class="progress" data-value="60">
  <div class="progress-bar progress-warning"></div>
</div>
<div class="progress" data-value="30">
  <div class="progress-bar progress-error"></div>
</div>

<!-- Indeterminate (no value needed) -->
<div class="progress progress-indeterminate">
  <div class="progress-bar"></div>
</div>

<script>
// Initialize progress bars
document.querySelectorAll('.progress[data-value]').forEach(el => {
  const value = el.getAttribute('data-value');
  el.querySelector('.progress-bar').style.width = value + '%';
});

// Update progress dynamically
function setProgress(element, value) {
  const bar = element.querySelector('.progress-bar');
  bar.style.width = Math.min(100, Math.max(0, value)) + '%';
}
</script>

React

import { useState, useEffect } from 'react';

function ProgressDemo() {
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      setProgress((prev) => (prev >= 100 ? 0 : prev + 10));
    }, 500);
    return () => clearInterval(timer);
  }, []);

  return (
    <div>
      {/* Monochrome */}
      <div className="progress">
        <div className="progress-bar" style={{ width: `${progress}%` }} />
      </div>

      {/* Colored */}
      <div className="progress">
        <div className="progress-bar progress-success" style={{ width: '100%' }} />
      </div>

      {/* Indeterminate */}
      <div className="progress progress-indeterminate">
        <div className="progress-bar" />
      </div>
    </div>
  );
}

Vue

<template>
  <div>
    <!-- Monochrome -->
    <div class="progress">
      <div class="progress-bar" :style="{ width: progress + '%' }" />
    </div>

    <!-- Colored -->
    <div class="progress">
      <div class="progress-bar progress-success" style="width: 100%" />
    </div>

    <!-- Indeterminate -->
    <div class="progress progress-indeterminate">
      <div class="progress-bar" />
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

const progress = ref(0);
let timer;

onMounted(() => {
  timer = setInterval(() => {
    progress.value = progress.value >= 100 ? 0 : progress.value + 10;
  }, 500);
});

onUnmounted(() => clearInterval(timer));
</script>

jQuery

// Animate progress
let progress = 0;
setInterval(() => {
  progress = progress >= 100 ? 0 : progress + 10;
  $('.progress-bar').css('width', progress + '%');
}, 500);

// Set specific progress
$('.progress-bar').css('width', '75%');

// Add classes dynamically
$('.progress-bar').addClass('progress-success');
$('.progress-bar').addClass('progress-striped progress-animated');

Buttons CSS

Flexible button system with multiple variants (primary, secondary, ghost, outline, text) and sizes (xs, sm, md, lg, xl). Includes disabled and loading states.

Button Variants

HTML/CSS

<button class="btn btn-primary">Primary</button>
<button class="btn btn-secondary">Secondary</button>

React

import { Button } from '@monochrome-edge/ui/react';

<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>

Vue.js

<template>
  <Button variant="primary">Primary</Button>
  <Button variant="secondary">Secondary</Button>
</template>

<script setup>
import { Button } from '@monochrome-edge/ui/vue';
</script>

Web Components

<mce-button variant="primary">Primary</mce-button>
<mce-button variant="secondary">Secondary</mce-button>

<script type="module">
  import '@monochrome-edge/ui/wc';
</script>

jQuery

$('<button>').addClass('btn btn-primary').text('Primary').appendTo('#app');
$('<button>').addClass('btn btn-secondary').text('Secondary').appendTo('#app');

Vanilla JavaScript

import { createButton } from '@monochrome-edge/ui';

const btn1 = createButton('Primary', { variant: 'primary' });
const btn2 = createButton('Secondary', { variant: 'secondary' });
document.body.appendChild(btn1);
document.body.appendChild(btn2);

Button Sizes

HTML/CSS

<button class="btn btn-primary btn-small">Small</button>
<button class="btn btn-primary">Default</button>
<button class="btn btn-primary btn-large">Large</button>

React

import { Button } from '@monochrome-edge/ui/react';

<Button size="small">Small</Button>
<Button>Default</Button>
<Button size="large">Large</Button>

Vue.js

<template>
  <Button size="small">Small</Button>
  <Button>Default</Button>
  <Button size="large">Large</Button>
</template>

<script setup>
import { Button } from '@monochrome-edge/ui/vue';
</script>

Web Components

<mce-button size="small">Small</mce-button>
<mce-button>Default</mce-button>
<mce-button size="large">Large</mce-button>

<script type="module">
  import '@monochrome-edge/ui/wc';
</script>

jQuery

$('<button>').addClass('btn btn-primary btn-small').text('Small').appendTo('#app');
$('<button>').addClass('btn btn-primary').text('Default').appendTo('#app');
$('<button>').addClass('btn btn-primary btn-large').text('Large').appendTo('#app');

Vanilla JavaScript

import { createButton } from '@monochrome-edge/ui';

const btnSmall = createButton('Small', { variant: 'primary', size: 'small' });
const btnDefault = createButton('Default', { variant: 'primary' });
const btnLarge = createButton('Large', { variant: 'primary', size: 'large' });
document.body.appendChild(btnSmall);
document.body.appendChild(btnDefault);
document.body.appendChild(btnLarge);

Icon Buttons CSSSVG

Icon-only buttons with multiple variants, sizes, and states for intuitive actions.

Icon Options

HTML/CSS

<!-- Using package icons -->
<button class="icon-btn">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn icon-btn-primary">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn icon-btn-ghost">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn icon-btn-outline">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>

<!-- Or copy icons to your project -->
<button class="icon-btn">
  <img src="assets/icons/sun.svg" class="icon" alt="Sun">
</button>

React

import { IconButton } from '@monochrome-edge/react';

<IconButton icon="sun" variant="default" />
<IconButton icon="sun" variant="primary" />
<IconButton icon="sun" variant="ghost" />
<IconButton icon="sun" variant="outline" />

Vue.js

<template>
  <IconButton icon="sun" variant="default" />
  <IconButton icon="sun" variant="primary" />
  <IconButton icon="sun" variant="ghost" />
  <IconButton icon="sun" variant="outline" />
</template>

<script setup>
import { IconButton } from '@monochrome-edge/vue';
</script>

Web Components

<mce-icon-button icon="sun" variant="default"></mce-icon-button>
<mce-icon-button icon="sun" variant="primary"></mce-icon-button>
<mce-icon-button icon="sun" variant="ghost"></mce-icon-button>
<mce-icon-button icon="sun" variant="outline"></mce-icon-button>

<script type="module">
  import '@monochrome-edge/web-components';
</script>

jQuery

const btn1 = $.createIconButton({ icon: 'sun', variant: 'default' });
const btn2 = $.createIconButton({ icon: 'sun', variant: 'primary' });
const btn3 = $.createIconButton({ icon: 'sun', variant: 'ghost' });
const btn4 = $.createIconButton({ icon: 'sun', variant: 'outline' });

Vanilla JavaScript

import { createIconButton } from '@monochrome-edge/vanilla-ts';

const btn1 = createIconButton({ icon: 'sun', variant: 'default' });
const btn2 = createIconButton({ icon: 'sun', variant: 'primary' });
const btn3 = createIconButton({ icon: 'sun', variant: 'ghost' });
const btn4 = createIconButton({ icon: 'sun', variant: 'outline' });

Icon Resources:

Variants

HTML/CSS

<!-- Using package icons -->
<button class="icon-btn">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn icon-btn-primary">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn icon-btn-ghost">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn icon-btn-outline">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>

<!-- Or copy icons to your project -->
<button class="icon-btn">
  <img src="assets/icons/sun.svg" class="icon" alt="Sun">
</button>

React

import { IconButton } from '@monochrome-edge/react';

<IconButton icon="sun" variant="default" />
<IconButton icon="sun" variant="primary" />
<IconButton icon="sun" variant="ghost" />
<IconButton icon="sun" variant="outline" />

Vue.js

<template>
  <IconButton icon="sun" variant="default" />
  <IconButton icon="sun" variant="primary" />
  <IconButton icon="sun" variant="ghost" />
  <IconButton icon="sun" variant="outline" />
</template>

<script setup>
import { IconButton } from '@monochrome-edge/vue';
</script>

Web Components

<mce-icon-button icon="sun" variant="default"></mce-icon-button>
<mce-icon-button icon="sun" variant="primary"></mce-icon-button>
<mce-icon-button icon="sun" variant="ghost"></mce-icon-button>
<mce-icon-button icon="sun" variant="outline"></mce-icon-button>

<script type="module">
  import '@monochrome-edge/web-components';
</script>

jQuery

const btn1 = $.createIconButton({ icon: 'sun', variant: 'default' });
const btn2 = $.createIconButton({ icon: 'sun', variant: 'primary' });
const btn3 = $.createIconButton({ icon: 'sun', variant: 'ghost' });
const btn4 = $.createIconButton({ icon: 'sun', variant: 'outline' });

Vanilla JavaScript

import { createIconButton } from '@monochrome-edge/vanilla-ts';

const btn1 = createIconButton({ icon: 'sun', variant: 'default' });
const btn2 = createIconButton({ icon: 'sun', variant: 'primary' });
const btn3 = createIconButton({ icon: 'sun', variant: 'ghost' });
const btn4 = createIconButton({ icon: 'sun', variant: 'outline' });

Sizes

HTML/CSS

<!-- Using package icons -->
<button class="icon-btn icon-btn-sm">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn icon-btn-md">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn icon-btn-lg">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn icon-btn-xl">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>

<!-- Or copy icons to your project -->
<button class="icon-btn icon-btn-md">
  <img src="assets/icons/sun.svg" class="icon" alt="Sun">
</button>

React

<IconButton icon="sun" size="sm" />
<IconButton icon="sun" size="md" />
<IconButton icon="sun" size="lg" />
<IconButton icon="sun" size="xl" />

Vue.js

<IconButton icon="sun" size="sm" />
<IconButton icon="sun" size="md" />
<IconButton icon="sun" size="lg" />
<IconButton icon="sun" size="xl" />

jQuery

$.createIconButton({ icon: 'sun', size: 'sm' });
$.createIconButton({ icon: 'sun', size: 'md' });
$.createIconButton({ icon: 'sun', size: 'lg' });
$.createIconButton({ icon: 'sun', size: 'xl' });

Web Components

<mce-icon-button icon="sun" size="sm"></mce-icon-button>
<mce-icon-button icon="sun" size="md"></mce-icon-button>
<mce-icon-button icon="sun" size="lg"></mce-icon-button>
<mce-icon-button icon="sun" size="xl"></mce-icon-button>

<script type="module">
  import '@monochrome-edge/web-components';
</script>

Vanilla JavaScript

import { createIconButton } from '@monochrome-edge/vanilla-ts';

const btnSm = createIconButton({ icon: 'sun', size: 'sm' });
const btnMd = createIconButton({ icon: 'sun', size: 'md' });
const btnLg = createIconButton({ icon: 'sun', size: 'lg' });
const btnXl = createIconButton({ icon: 'sun', size: 'xl' });

States

HTML/CSS

<!-- Using package icons -->
<button class="icon-btn">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn active">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn" disabled>
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>
<button class="icon-btn loading">
  <img src="https://cdn.jsdelivr.net/npm/@monochrome-edge/ui/assets/icons/sun.svg" class="icon" alt="Sun">
</button>

<!-- Or copy icons to your project -->
<button class="icon-btn">
  <img src="assets/icons/sun.svg" class="icon" alt="Sun">
</button>

React

<IconButton icon="sun" />
<IconButton icon="sun" active />
<IconButton icon="sun" disabled />
<IconButton icon="sun" loading />

Vue.js

<IconButton icon="sun" />
<IconButton icon="sun" :active="true" />
<IconButton icon="sun" :disabled="true" />
<IconButton icon="sun" :loading="true" />

Toggle

Theme

Warm ↔ Cold

Mode

Light ↔ Dark

Color

Mono ↔ Color

Language

KO → EN → CN → JP

Click toggles to see animations:
Theme: Vertical slide with warm/cold gradient transition
Mode: Horizontal slide with light→dark gradient
Color: Instant toggle with gradient background
Language: Multi-language cycle (KO → EN → CN → JP) with diagonal animation

HTML

<!-- Theme Toggle (Warm ↔ Cold) -->
<button class="icon-btn-toggle icon-btn-toggle-theme" data-state="warm">
    <div class="icon-btn-toggle-overlay"></div>
    <div class="icon-btn-toggle-icon">
        <svg>...flame icon...</svg>
        <svg>...snowflake icon...</svg>
    </div>
</button>

<!-- Mode Toggle (Light ↔ Dark) -->
<button class="icon-btn-toggle icon-btn-toggle-mode" data-state="light">
    <div class="icon-btn-toggle-overlay"></div>
    <div class="icon-btn-toggle-icon">
        <svg>...sun icon...</svg>
        <svg>...moon icon...</svg>
    </div>
</button>

<!-- Color Toggle (Monochrome ↔ Colored) -->
<button class="icon-btn-toggle icon-btn-toggle-colored" data-state="monochrome">
    <div class="icon-btn-toggle-overlay"></div>
    <div class="icon-btn-toggle-icon">
        <svg>...palette icon...</svg>
    </div>
</button>

<!-- Language Toggle (KO ↔ EN) -->
<button class="language-toggle" data-toggled="false">
    <div class="language-toggle-text">
        <span class="lang-first">KO</span>
        <span class="lang-slash"></span>
        <span class="lang-second">EN</span>
    </div>
</button>

JavaScript

// Theme toggle with vertical animation
const themeToggle = document.querySelector('.icon-btn-toggle-theme');
themeToggle.addEventListener('click', function() {
    const current = this.dataset.state;
    const next = current === 'warm' ? 'cold' : 'warm';

    this.dataset.transitioning = `${current}-to-${next}`;
    this.classList.add('is-animating');

    setTimeout(() => {
        this.dataset.state = next;
        this.removeAttribute('data-transitioning');
        this.classList.remove('is-animating');
        document.documentElement.setAttribute('data-theme-variant', next);
    }, 600);
});

// Mode toggle with horizontal animation
const modeToggle = document.querySelector('.icon-btn-toggle-mode');
modeToggle.addEventListener('click', function() {
    const current = this.dataset.state;
    const next = current === 'light' ? 'dark' : 'light';

    this.dataset.transitioning = `${current}-to-${next}`;
    this.classList.add('is-animating');

    setTimeout(() => {
        this.dataset.state = next;
        this.removeAttribute('data-transitioning');
        this.classList.remove('is-animating');
        document.documentElement.setAttribute('data-theme', next);
    }, 700);
});

// Color toggle (instant)
const colorToggle = document.querySelector('.icon-btn-toggle-colored');
colorToggle.addEventListener('click', function() {
    const current = this.dataset.state;
    const next = current === 'colored' ? 'monochrome' : 'colored';
    this.dataset.state = next;
});

// Language toggle with diagonal flip animation
const languageToggle = document.querySelector('.language-toggle');
languageToggle.addEventListener('click', function() {
    const isToggled = this.dataset.toggled === 'true';
    this.classList.add('is-animating');

    setTimeout(() => {
        this.dataset.toggled = !isToggled;
        this.classList.remove('is-animating');
    }, 500);
});

Features

  • Gradient animations: Uses landscape theme colors for authentic transitions
  • State indicators: Small colored dots show current state
  • Smooth transitions: Icon slides combined with color gradients
  • Data attributes: data-state and data-transitioning for styling
  • Accessibility: Proper focus states and ARIA labels

Web Components

<!-- Theme Toggle -->
<mce-icon-toggle type="theme"></mce-icon-toggle>

<!-- Mode Toggle -->
<mce-icon-toggle type="mode"></mce-icon-toggle>

<!-- Color Toggle -->
<mce-icon-toggle type="color"></mce-icon-toggle>

<!-- Language Toggle -->
<mce-icon-toggle type="language"></mce-icon-toggle>

<!-- Ghost variant -->
<mce-icon-toggle type="mode" variant="ghost"></mce-icon-toggle>

<script>
  // Listen to toggle events
  document.querySelector('mce-icon-toggle').addEventListener('toggle', (e) => {
    console.log('Toggled to:', e.detail.state);
  });
</script>

React

import { IconToggle } from '@monochrome-edge/react';

function MyComponent() {
  const handleToggle = (state) => {
    console.log('Toggled to:', state);
  };

  return (
    <div style={{ display: 'flex', gap: '1rem' }}>
      {/* Theme Toggle */}
      <IconToggle
        type="theme"
        onToggle={handleToggle}
      />

      {/* Mode Toggle */}
      <IconToggle
        type="mode"
        onToggle={handleToggle}
      />

      {/* Color Toggle */}
      <IconToggle
        type="color"
        onToggle={handleToggle}
      />

      {/* Language Toggle */}
      <IconToggle
        type="language"
        onToggle={handleToggle}
      />

      {/* Ghost variant */}
      <IconToggle
        type="mode"
        variant="ghost"
        onToggle={handleToggle}
      />
    </div>
  );
}

Vue

<template>
  <div style="display: flex; gap: 1rem">
    <!-- Theme Toggle -->
    <IconToggle
      type="theme"
      @toggle="handleToggle"
    />

    <!-- Mode Toggle -->
    <IconToggle
      type="mode"
      @toggle="handleToggle"
    />

    <!-- Color Toggle -->
    <IconToggle
      type="color"
      @toggle="handleToggle"
    />

    <!-- Language Toggle -->
    <IconToggle
      type="language"
      @toggle="handleToggle"
    />

    <!-- Ghost variant -->
    <IconToggle
      type="mode"
      variant="ghost"
      @toggle="handleToggle"
    />
  </div>
</template>

<script setup>
import { IconToggle } from '@monochrome-edge/vue';

const handleToggle = (state) => {
  console.log('Toggled to:', state);
};
</script>

jQuery

// Theme toggle
$('#theme-toggle').mceIconToggle({
  type: 'theme',
  onToggle: function(state) {
    console.log('Theme:', state);
  }
});

// Mode toggle
$('#mode-toggle').mceIconToggle({
  type: 'mode',
  onToggle: function(state) {
    console.log('Mode:', state);
  }
});

// Color toggle
$('#color-toggle').mceIconToggle({
  type: 'color',
  onToggle: function(state) {
    console.log('Color:', state);
  }
});

// Language toggle
$('#language-toggle').mceIconToggle({
  type: 'language',
  onToggle: function(state) {
    console.log('Language:', state);
  }
});

// Ghost variant
$('#ghost-toggle').mceIconToggle({
  type: 'mode',
  variant: 'ghost'
});

Forms CSS

Comprehensive form components including text inputs, textareas, selects, checkboxes, radio buttons, and switches. Features validation states (success, warning, error) and disabled states.

Form Elements

We'll never share your email.

HTML/CSS

<div class="form-group">
    <label class="label">Email Address</label>
    <input type="email" class="input" placeholder="you@example.com">
    <span class="helper-text">We'll never share your email.</span>
</div>

React

import { Input } from '@monochrome-edge/ui/react';

<Input
    label="Email Address"
    type="email"
    placeholder="you@example.com"
    helperText="We'll never share your email."
/>

Vue.js

<Input
    label="Email Address"
    type="email"
    placeholder="you@example.com"
    helper-text="We'll never share your email."
/>

Web Components

<mce-input
    label="Email Address"
    type="email"
    placeholder="you@example.com"
    helper-text="We'll never share your email."
></mce-input>

<script type="module">
  import '@monochrome-edge/ui/wc';
</script>

jQuery

$('#email-input').wrap('<div class="form-group"></div>');
$('#email-input').before('<label class="label">Email Address</label>');
$('#email-input').after('<span class="helper-text">We\'ll never share your email.</span>');

Icon Button Toggle CSS JS

Animated toggle buttons for theme (warm/cold), mode (light/dark), and color options with smooth gradient transitions.

Theme & Mode Toggles

Theme

Mode

Color

HTML

<!-- Theme Toggle -->
<button class="icon-btn-toggle icon-btn-toggle-theme" data-state="warm">
    <div class="icon-btn-toggle-overlay"></div>
    <div class="icon-btn-toggle-icon">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">
            <path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"/>
        </svg>
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">
            <path d="M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M6.34 6.34L4.93 4.93m12.73 14.14l1.41 1.41"/>
            <path d="M12 7c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5z"/>
        </svg>
    </div>
</button>

<!-- Mode Toggle -->
<button class="icon-btn-toggle icon-btn-toggle-mode" data-state="light">
    <div class="icon-btn-toggle-overlay"></div>
    <div class="icon-btn-toggle-icon">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">
            <circle cx="12" cy="12" r="4"/>
            <!-- sun rays -->
        </svg>
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">
            <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>
        </svg>
    </div>
</button>

<!-- Colored/Monochrome Toggle -->
<button class="icon-btn-toggle icon-btn-toggle-colored" data-state="monochrome">
    <div class="icon-btn-toggle-overlay"></div>
    <div class="icon-btn-toggle-icon">
        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24">
            <!-- palette icon -->
        </svg>
    </div>
</button>

JavaScript

// Theme toggle with animation
const themeToggle = document.querySelector('.icon-btn-toggle-theme');
themeToggle.addEventListener('click', function() {
    const current = this.dataset.state;
    const next = current === 'warm' ? 'cold' : 'warm';

    // Set transition direction
    this.dataset.transitioning = `${current}-to-${next}`;

    // Update state after animation
    setTimeout(() => {
        this.dataset.state = next;
        this.removeAttribute('data-transitioning');

        // Apply theme to document
        document.documentElement.setAttribute('data-theme-variant', next);
    }, 500);
});

// Mode toggle with animation
const modeToggle = document.querySelector('.icon-btn-toggle-mode');
modeToggle.addEventListener('click', function() {
    const current = this.dataset.state;
    const next = current === 'light' ? 'dark' : 'light';

    this.dataset.transitioning = `${current}-to-${next}`;

    setTimeout(() => {
        this.dataset.state = next;
        this.removeAttribute('data-transitioning');

        // Apply mode to document
        document.documentElement.setAttribute('data-theme', next);
    }, 700);
});

// Color mode toggle
const colorToggle = document.querySelector('.icon-btn-toggle-colored');
colorToggle.addEventListener('click', function() {
    const current = this.dataset.state;
    const next = current === 'colored' ? 'monochrome' : 'colored';
    this.dataset.state = next;
});

Web Components

<!-- Theme Toggle -->
<mce-icon-toggle
  type="theme"
  variant="default"
></mce-icon-toggle>

<!-- Mode Toggle -->
<mce-icon-toggle
  type="mode"
></mce-icon-toggle>

<!-- Color Toggle -->
<mce-icon-toggle
  type="color"
></mce-icon-toggle>

<!-- Language Toggle -->
<mce-icon-toggle
  type="language"
></mce-icon-toggle>

<!-- Ghost variant -->
<mce-icon-toggle
  type="mode"
  variant="ghost"
></mce-icon-toggle>

<script>
  // Listen to toggle events
  document.querySelector('mce-icon-toggle').addEventListener('toggle', (e) => {
    console.log('Toggled to:', e.detail.state);
  });
</script>

React

import { IconToggle } from '@monochrome-edge/react';

function MyComponent() {
  const handleToggle = (state) => {
    console.log('New state:', state);
  };

  return (
    <div style={{ display: 'flex', gap: '1rem' }}>
      {/* Theme Toggle */}
      <IconToggle
        type="theme"
        onToggle={handleToggle}
      />

      {/* Mode Toggle */}
      <IconToggle
        type="mode"
        onToggle={handleToggle}
      />

      {/* Color Toggle */}
      <IconToggle
        type="color"
        onToggle={handleToggle}
      />

      {/* Language Toggle */}
      <IconToggle
        type="language"
        onToggle={handleToggle}
      />

      {/* Ghost variant */}
      <IconToggle
        type="mode"
        variant="ghost"
        onToggle={handleToggle}
      />

      {/* Disabled */}
      <IconToggle
        type="theme"
        disabled
      />
    </div>
  );
}

Vue

<template>
  <div style="display: flex; gap: 1rem">
    <!-- Theme Toggle -->
    <IconToggle
      type="theme"
      @toggle="handleToggle"
    />

    <!-- Mode Toggle -->
    <IconToggle
      type="mode"
      @toggle="handleToggle"
    />

    <!-- Color Toggle -->
    <IconToggle
      type="color"
      @toggle="handleToggle"
    />

    <!-- Language Toggle -->
    <IconToggle
      type="language"
      @toggle="handleToggle"
    />

    <!-- Ghost variant -->
    <IconToggle
      type="mode"
      variant="ghost"
      @toggle="handleToggle"
    />

    <!-- Disabled -->
    <IconToggle
      type="theme"
      :disabled="true"
    />
  </div>
</template>

<script setup>
import { IconToggle } from '@monochrome-edge/vue';

const handleToggle = (state) => {
  console.log('New state:', state);
};
</script>

jQuery

// Theme toggle
$('#theme-toggle').mceIconToggle({
  type: 'theme',
  variant: 'default',
  onToggle: function(state) {
    console.log('Theme toggled to:', state);
  }
});

// Mode toggle
$('#mode-toggle').mceIconToggle({
  type: 'mode',
  onToggle: function(state) {
    console.log('Mode toggled to:', state);
  }
});

// Color toggle
$('#color-toggle').mceIconToggle({
  type: 'color',
  onToggle: function(state) {
    console.log('Color mode:', state);
  }
});

// Language toggle
$('#language-toggle').mceIconToggle({
  type: 'language',
  onToggle: function(state) {
    console.log('Language:', state);
  }
});

// Ghost variant
$('#ghost-toggle').mceIconToggle({
  type: 'mode',
  variant: 'ghost'
});

// Disabled
$('#disabled-toggle').mceIconToggle({
  type: 'theme',
  disabled: true
});

Animation Details

  • Theme (Warm ↔ Cold): Vertical slide animation with blue-to-red gradient transition
  • Mode (Light ↔ Dark): Horizontal slide animation with light→warm→cool→dark gradient
  • Color Toggle: Instant state change with gradient background when colored
  • State Indicators: Small colored dots at bottom-right show current state
  • Landscape Colors: Uses theme landscape colors for authentic gradients

Search CSSJS

Powerful search with fuzzy autocomplete, filters, and tag selection. Type to search, select suggestions to add as tags, and use filters to refine your results. Perfect for documentation, e-commerce, and content management.

Search Toolbar

Vanilla JS

import { SearchToolbar } from '@monochrome-edge/ui';

// Basic usage
const toolbar = new MonochromeEdge.SearchToolbar('#search-toolbar', {
  placeholder: 'Search...',
  onSearch: (query) => {
    console.log('Search:', query);
    // Your search logic here
  }
});

// With autocomplete
const toolbarWithAutocomplete = new MonochromeEdge.SearchToolbar('#search-toolbar', {
  placeholder: 'Search components...',
  autocomplete: async (query) => {
    const items = ['React', 'Vue', 'Angular', 'Svelte'];
    return items.filter(item =>
      item.toLowerCase().includes(query.toLowerCase())
    );
  },
  onSearch: (query) => {
    // Handle search
  }
});

// Advanced: With filters and sort (see full docs)
const advancedToolbar = new MonochromeEdge.SearchToolbar('#search-toolbar', {
  placeholder: 'Advanced search...',
  filters: [/* filter config */],
  sortOptions: [/* sort config */],
  onSearch: (query, filters, sort) => {
    // Handle advanced search
  }
});

React

import { SearchToolbar } from '@monochrome-edge/react';

function SearchExample() {
  const handleSearch = (query, filters, sort) => {
    console.log('Search:', { query, filters, sort });
    // Perform your search logic here
  };

  return (
    <SearchToolbar
      placeholder="Search components..."
      autocomplete={async (query) => {
        const items = ['React', 'Vue', 'Angular', 'Svelte'];
        return items.filter(item =>
          item.toLowerCase().includes(query.toLowerCase())
        );
      }}
      filters={[
        {
          id: 'category',
          label: 'Category',
          values: [
            { value: 'all', label: 'All' },
            { value: 'components', label: 'Components' }
          ],
          default: 'all'
        }
      ]}
      sortOptions={[
        { value: 'relevance', label: 'Relevance' },
        { value: 'name', label: 'Name' }
      ]}
      onSearch={handleSearch}
    />
  );
}

Vue

<template>
  <SearchToolbar
    placeholder="Search components..."
    :autocomplete="handleAutocomplete"
    :filters="filters"
    :sort-options="sortOptions"
    @search="handleSearch"
  />
</template>

<script setup>
import { SearchToolbar } from '@monochrome-edge/vue';

const handleAutocomplete = async (query) => {
  const items = ['React', 'Vue', 'Angular', 'Svelte'];
  return items.filter(item =>
    item.toLowerCase().includes(query.toLowerCase())
  );
};

const filters = [
  {
    id: 'category',
    label: 'Category',
    values: [
      { value: 'all', label: 'All' },
      { value: 'components', label: 'Components' }
    ],
    default: 'all'
  }
];

const sortOptions = [
  { value: 'relevance', label: 'Relevance' },
  { value: 'name', label: 'Name' }
];

const handleSearch = (query, filters, sort) => {
  console.log('Search:', { query, filters, sort });
  // Perform your search logic here
};
</script>

Web Components

<mce-search-toolbar
  placeholder="Search components..."
  id="search-toolbar"
></mce-search-toolbar>

<script type="module">
  import '@monochrome-edge/web-components';

  const searchToolbar = document.getElementById('search-toolbar');

  searchToolbar.addEventListener('search', (e) => {
    console.log('Search:', e.detail);
  });

  // Set autocomplete function
  searchToolbar.setAutocomplete(async (query) => {
    const items = ['React', 'Vue', 'Angular', 'Svelte'];
    return items.filter(item =>
      item.toLowerCase().includes(query.toLowerCase())
    );
  });
</script>

jQuery

$('#search-container').searchToolbar({
  placeholder: 'Search components...',
  autocomplete: async (query) => {
    const items = ['React', 'Vue', 'Angular', 'Svelte'];
    return items.filter(item =>
      item.toLowerCase().includes(query.toLowerCase())
    );
  },
  filters: [
    {
      id: 'category',
      label: 'Category',
      values: [
        { value: 'all', label: 'All' },
        { value: 'components', label: 'Components' }
      ],
      default: 'all'
    }
  ],
  sortOptions: [
    { value: 'relevance', label: 'Relevance' },
    { value: 'name', label: 'Name' }
  ],
  onSearch: (query, filters, sort) => {
    console.log('Search:', { query, filters, sort });
  }
});

Search Input

Expandable search input with underbar animation. Hover to preview, click to expand with autocomplete.

HTML/CSS

<!-- Expandable search input with underbar animation -->
<div class="search-input" id="search-input">
    <svg class="search-input-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
        <circle cx="11" cy="11" r="8"></circle>
        <path d="m21 21-4.35-4.35"></path>
    </svg>
    <input
        type="text"
        class="search-input-field"
        placeholder="Search documentation..."
    />
    <button class="search-input-cancel" type="button">×</button>
    <div class="search-input-suggestions"></div>
</div>

<script>
const searchInput = document.getElementById('search-input');
const searchField = searchInput.querySelector('.search-input-field');
const searchCancel = searchInput.querySelector('.search-input-cancel');
const suggestions = searchInput.querySelector('.search-input-suggestions');

// Expand on click
searchInput.addEventListener('click', () => {
    searchInput.classList.add('is-expanded');
    searchField.focus();
});

// Cancel button
searchCancel.addEventListener('click', (e) => {
    e.stopPropagation();
    searchField.value = '';
    searchInput.classList.remove('is-expanded');
    suggestions.classList.remove('is-visible');
});

// Collapse on outside click
document.addEventListener('click', (e) => {
    if (!searchInput.contains(e.target)) {
        searchInput.classList.remove('is-expanded');
        suggestions.classList.remove('is-visible');
    }
});
</script>

React

import { useState, useRef, useEffect } from 'react';

function SearchInput({ onSearch, suggestions = [] }) {
  const [isExpanded, setIsExpanded] = useState(false);
  const [value, setValue] = useState('');
  const [showSuggestions, setShowSuggestions] = useState(false);
  const containerRef = useRef(null);

  useEffect(() => {
    const handleClickOutside = (e) => {
      if (containerRef.current && !containerRef.current.contains(e.target)) {
        setIsExpanded(false);
        setShowSuggestions(false);
      }
    };
    document.addEventListener('click', handleClickOutside);
    return () => document.removeEventListener('click', handleClickOutside);
  }, []);

  return (
    <div
      ref={containerRef}
      className={`search-input ${isExpanded ? 'is-expanded' : ''}`}
      onClick={() => setIsExpanded(true)}
    >
      <svg className="search-input-icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
        <circle cx="11" cy="11" r="8" />
        <path d="m21 21-4.35-4.35" />
      </svg>
      <input
        type="text"
        className="search-input-field"
        placeholder="Search documentation..."
        value={value}
        onChange={(e) => {
          setValue(e.target.value);
          setShowSuggestions(e.target.value.length > 0);
        }}
      />
      <button
        className="search-input-cancel"
        onClick={(e) => {
          e.stopPropagation();
          setValue('');
          setIsExpanded(false);
          setShowSuggestions(false);
        }}
      >×</button>
      <div className={`search-input-suggestions ${showSuggestions ? 'is-visible' : ''}`}>
        {/* Suggestion items */}
      </div>
    </div>
  );
}

Features

  • Icon-only collapsed state: Shows only search icon initially
  • Hover preview: Underbar appears on hover showing input preview
  • Click expansion: Clicking icon or container expands with underbar animation
  • Icon slide: Search icon slides to the left on expansion
  • Cancel button: Appears on the right when expanded
  • Autocomplete: Shows suggestions based on current document sections
  • Keyboard navigation: Arrow keys and Enter for suggestion selection
  • Responsive: Full-width on mobile devices

Cards CSS

Versatile card components for displaying grouped content with headers, body, footer, and action areas. Includes elevated, outlined, and interactive hover states.

Card Types

Card Title

This is a basic card with header and body.

Total Revenue
$45,231
+12.5%

HTML/CSS

<!-- Basic Card -->
<div class="card">
    <div class="card-header">
        <h4 class="card-header-title">Card Title</h4>
    </div>
    <div class="card-body">
        <p>Card content</p>
    </div>
</div>

<!-- Stat Card -->
<div class="stat-card">
    <div class="stat-card-label">Total Revenue</div>
    <div class="stat-card-value">$45,231</div>
    <div class="stat-card-change stat-card-change-positive">+12.5%</div>
</div>

React

import { Card } from '@monochrome-edge/ui/react';

<Card title="Card Title">
    <p>Card content</p>
</Card>

Vue.js

<Card title="Card Title">
    <p>Card content</p>
</Card>

Web Components

<mce-card title="Card Title">
    <p>Card content</p>
</mce-card>

<script type="module">
  import '@monochrome-edge/ui/wc';
</script>

jQuery

// Create card dynamically
const $card = $('<div>').addClass('card');
const $header = $('<div>').addClass('card-header');
const $title = $('<h4>').addClass('card-header-title').text('Card Title');
const $body = $('<div>').addClass('card-body');
const $content = $('<p>').text('Card content');

$header.append($title);
$body.append($content);
$card.append($header, $body);
$('#container').append($card);

Modals CSSJS

Modal dialogs for user interactions and confirmations.

Modal Example

Tables CSS

Data tables for displaying structured information.

Data Table

Name Status Role Actions
John Doe Active Admin
Jane Smith Pending User

HTML/CSS

<div class="table-container">
    <table class="data-table">
        <thead>
            <tr>
                <th>Name</th>
                <th>Status</th>
                <th>Role</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>John Doe</td>
                <td><span class="badge badge-success">Active</span></td>
                <td>Admin</td>
                <td><button class="btn btn-ghost btn-small">Edit</button></td>
            </tr>
        </tbody>
    </table>
</div>

React

import { Table, Badge, Button } from '@monochrome-edge/ui/react';

const data = [
    { name: 'John Doe', status: 'active', role: 'Admin' },
    { name: 'Jane Smith', status: 'pending', role: 'User' }
];

<Table>
    <Table.Header>
        <Table.Row>
            <Table.HeaderCell>Name</Table.HeaderCell>
            <Table.HeaderCell>Status</Table.HeaderCell>
            <Table.HeaderCell>Role</Table.HeaderCell>
            <Table.HeaderCell>Actions</Table.HeaderCell>
        </Table.Row>
    </Table.Header>
    <Table.Body>
        {data.map((user) => (
            <Table.Row key={user.name}>
                <Table.Cell>{user.name}</Table.Cell>
                <Table.Cell>
                    <Badge variant={user.status === 'active' ? 'success' : 'warning'}>
                        {user.status}
                    </Badge>
                </Table.Cell>
                <Table.Cell>{user.role}</Table.Cell>
                <Table.Cell>
                    <Button variant="ghost" size="small">Edit</Button>
                </Table.Cell>
            </Table.Row>
        ))}
    </Table.Body>
</Table>

Vue.js

<Table>
    <TableHeader>
        <TableRow>
            <TableHeaderCell>Name</TableHeaderCell>
            <TableHeaderCell>Status</TableHeaderCell>
            <TableHeaderCell>Role</TableHeaderCell>
            <TableHeaderCell>Actions</TableHeaderCell>
        </TableRow>
    </TableHeader>
    <TableBody>
        <TableRow v-for="user in users" :key="user.name">
            <TableCell>{{ user.name }}</TableCell>
            <TableCell>
                <Badge :variant="user.status === 'active' ? 'success' : 'warning'">
                    {{ user.status }}
                </Badge>
            </TableCell>
            <TableCell>{{ user.role }}</TableCell>
            <TableCell>
                <Button variant="ghost" size="small">Edit</Button>
            </TableCell>
        </TableRow>
    </TableBody>
</Table>

jQuery

// Add row dynamically
$('#addRow').on('click', function() {
    const newRow = `
        <tr>
            <td>New User</td>
            <td><span class="badge badge-pending">Pending</span></td>
            <td>User</td>
            <td><button class="btn btn-ghost btn-small">Edit</button></td>
        </tr>
    `;
    $('.data-table tbody').append(newRow);
});

// Sort table
$('th').on('click', function() {
    // Sorting logic here
});

Web Components

<mce-table>
    <mce-table-header>
        <mce-table-row>
            <mce-table-header-cell>Name</mce-table-header-cell>
            <mce-table-header-cell>Status</mce-table-header-cell>
            <mce-table-header-cell>Role</mce-table-header-cell>
            <mce-table-header-cell>Actions</mce-table-header-cell>
        </mce-table-row>
    </mce-table-header>
    <mce-table-body>
        <mce-table-row>
            <mce-table-cell>John Doe</mce-table-cell>
            <mce-table-cell>
                <mce-badge variant="success">Active</mce-badge>
            </mce-table-cell>
            <mce-table-cell>Admin</mce-table-cell>
            <mce-table-cell>
                <mce-button variant="ghost" size="small">Edit</mce-button>
            </mce-table-cell>
        </mce-table-row>
    </mce-table-body>
</mce-table>

<script type="module">
  import '@monochrome-edge/web-components';
</script>

Layouts CSS

Pre-built layout templates for CMS and SaaS applications.

Doc Layout

Documentation
Getting Started
Installation
Quick Start
Components
Buttons
Forms
Cards
API Reference
Methods
Properties

Getting Started

Welcome to the documentation. This guide will help you get started with our design system and components.

Installation

npm install @monochrome-edge/ui

After installation, import the styles and components you need.

<div class="doc-layout">
  <aside class="doc-sidebar">
    <div class="doc-sidebar-header">
      <h2>Documentation</h2>
    </div>
    <nav class="doc-nav">
      <ul class="nav-list">
        <li><a href="#getting-started">Getting Started</a></li>
        <li><a href="#components">Components</a></li>
        <li><a href="#api">API Reference</a></li>
      </ul>
    </nav>
  </aside>
  <main class="doc-main">
    <article class="doc-article">
      <h1>Page Title</h1>
      <p>Content goes here...</p>
    </article>
  </main>
</div>

Blog Layout

Building a Modern Design System

Oct 13, 2025 · 5 min read · Design Systems

A design system is a collection of reusable components, guided by clear standards, that can be assembled together to build any number of applications.

In this article, we'll explore the key principles and practices for creating a maintainable and scalable design system.

Key Principles

Start with a solid foundation of design tokens, reusable components, and clear documentation.

Read More →

Recent Posts

Component Architecture
Oct 10, 2025
CSS Best Practices
Oct 8, 2025
Theming Guide
Oct 5, 2025

Tags

CSS Design React Vue TypeScript
<div class="blog-layout">
  <main class="blog-main">
    <article class="blog-article">
      <header class="article-header">
        <h1>Article Title</h1>
        <div class="article-meta">
          <span class="article-date">Oct 13, 2025</span>
          <span class="article-author">By John Doe</span>
        </div>
      </header>
      <div class="article-content">
        <p>Article content...</p>
      </div>
    </article>
  </main>
  <aside class="blog-sidebar">
    <div class="widget">
      <h3>Recent Posts</h3>
      <ul>...</ul>
    </div>
    <div class="widget">
      <h3>Tags</h3>
      <div class="tag-cloud">...</div>
    </div>
  </aside>
</div>

Timeline CSS

Chronological display of events and milestones with various styles.

Timeline Variants

2 hours ago

Project Created

New project "Monochrome Edge" has been initialized with base configuration.

1 hour ago

Build Successful

Production build completed successfully with no errors.

30 minutes ago

Deployment Started

Application deployment to production environment initiated.

<div class="timeline">
    <div class="timeline-item">
        <div class="timeline-marker timeline-marker-dot">
            <div class="timeline-dot"></div>
        </div>
        <div class="timeline-content">
            <span class="timeline-time">2 hours ago</span>
            <h4 class="timeline-title">Project Created</h4>
            <p class="timeline-description">New project initialized.</p>
        </div>
    </div>
    <div class="timeline-item timeline-success">
        <div class="timeline-marker timeline-marker-dot">
            <div class="timeline-dot"></div>
        </div>
        <div class="timeline-content">
            <span class="timeline-time">1 hour ago</span>
            <h4 class="timeline-title">Build Successful</h4>
            <p class="timeline-description">Build completed.</p>
        </div>
    </div>
</div>

Stepper CSS SVG JS

Interactive step indicators with SVG-based rendering for workflows, wizards, and progress tracking. Supports multiple layouts (horizontal, vertical, snake) and two types (default with circles, text with buttons). Features automatic responsive behavior and smart popup positioning.

Stepper (Horizontal)

<!-- HTML: Declarative API -->
<div class="stepper"
     data-type="default"
     data-layout="horizontal"
     data-steps='[
         {
           "indicator": "1",
           "labelTitle": "Account Setup hellow asdfdsafdsa",
           "labelDesc": "Create your profile",
           "state": "completed",
           "title": "Account Setup adfasdfdsafas",
           "desc": "Create your account and set up your profile."
         },
         {
           "indicator": "2",
           "labelTitle": "Verification",
           "labelDesc": "Verify email",
           "state": "failed",
           "title": "Email Verification Failed",
           "desc": "Email verification failed. Please check your email."
         },
         {
           "indicator": "3",
           "labelTitle": "Preferences",
           "labelDesc": "Customize settings",
           "state": "pending",
           "title": "Set Preferences",
           "desc": "Customize your application settings."
         },
         {
           "indicator": "4",
           "labelTitle": "Confirmation",
           "labelDesc": "Review & confirm",
           "state": "pending",
           "title": "Final Confirmation",
           "desc": "Review all your settings and confirm to complete setup."
         }
     ]'>
</div>

<!-- States: pending, active, completed, failed -->

<!-- JavaScript: Programmatic API -->
<script>
const stepper = new MonochromeEdge.Stepper(container, {
  type: 'default',        // 'default' | 'text'
  layout: 'horizontal',   // 'horizontal' | 'vertical' | 'snake'
  onStepClick: (index, step) => {
    console.log('Step clicked:', index, step);
  }
});

// Update step state dynamically
stepper.updateStep(1, { state: 'completed' });
</script>

React

import { useState } from 'react';

function StepperDemo() {
  const [currentStep, setCurrentStep] = useState(0);
  const [steps, setSteps] = useState([
    { indicator: '1', labelTitle: 'Account Setup', state: 'completed' },
    { indicator: '2', labelTitle: 'Verification', state: 'active' },
    { indicator: '3', labelTitle: 'Preferences', state: 'pending' },
    { indicator: '4', labelTitle: 'Confirmation', state: 'pending' }
  ]);

  const nextStep = () => {
    setSteps(prev => prev.map((step, idx) => ({
      ...step,
      state: idx < currentStep + 1 ? 'completed' :
             idx === currentStep + 1 ? 'active' : 'pending'
    })));
    setCurrentStep(prev => Math.min(prev + 1, steps.length - 1));
  };

  return (
    <div>
      <div
        className="stepper"
        data-type="default"
        data-layout="horizontal"
        data-steps={JSON.stringify(steps)}
      />
      <button onClick={nextStep}>Next Step</button>
    </div>
  );
}

Vue

<template>
  <div>
    <div
      class="stepper"
      data-type="default"
      data-layout="horizontal"
      :data-steps="JSON.stringify(steps)"
    />
    <button @click="nextStep">Next Step</button>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const currentStep = ref(0);
const steps = ref([
  { indicator: '1', labelTitle: 'Account Setup', state: 'completed' },
  { indicator: '2', labelTitle: 'Verification', state: 'active' },
  { indicator: '3', labelTitle: 'Preferences', state: 'pending' },
  { indicator: '4', labelTitle: 'Confirmation', state: 'pending' }
]);

const nextStep = () => {
  steps.value = steps.value.map((step, idx) => ({
    ...step,
    state: idx < currentStep.value + 1 ? 'completed' :
           idx === currentStep.value + 1 ? 'active' : 'pending'
  }));
  currentStep.value = Math.min(currentStep.value + 1, steps.value.length - 1);
};
</script>

jQuery

// Initialize stepper
const $container = $('.stepper');
const stepper = new MonochromeEdge.Stepper($container[0], {
  type: 'default',
  layout: 'horizontal',
  onStepClick: (index, step) => {
    console.log('Step clicked:', index, step);
  }
});

// Update step state
$('#nextBtn').on('click', function() {
  const currentActive = stepper.steps.findIndex(s => s.state === 'active');
  if (currentActive >= 0) {
    stepper.updateStep(currentActive, { state: 'completed' });
    if (currentActive + 1 < stepper.steps.length) {
      stepper.updateStep(currentActive + 1, { state: 'active' });
    }
  }
});

// Add new step
stepper.addStep({
  indicator: '5',
  labelTitle: 'New Step',
  state: 'pending'
});

// Remove step
stepper.removeStep(stepper.steps.length - 1);

Stepper (Vertical)

<div class="stepper"
     data-type="default"
     data-layout="vertical"
     data-steps='[
         {"indicator":"1","labelTitle":"Account","labelDesc":"Setup","state":"completed","title":"Account Setup","desc":"Create your account and set up your profile information."},
         {"indicator":"2","labelTitle":"Verification","labelDesc":"Email","state":"completed","title":"Email Verification","desc":"Verify your email address to continue."},
         {"indicator":"3","labelTitle":"Preferences","labelDesc":"Settings","state":"active","title":"Set Preferences","desc":"Customize your application settings and preferences."},
         {"indicator":"4","labelTitle":"Confirmation","labelDesc":"Review","state":"pending","title":"Final Confirmation","desc":"Review all your settings and confirm to complete setup."}
     ]'>
</div>

React

import { useState, useEffect, useRef } from 'react';

function VerticalStepperDemo() {
  const containerRef = useRef(null);
  const [steps] = useState([
    { indicator: '1', labelTitle: 'Account', labelDesc: 'Setup', state: 'completed' },
    { indicator: '2', labelTitle: 'Verification', labelDesc: 'Email', state: 'completed' },
    { indicator: '3', labelTitle: 'Preferences', labelDesc: 'Settings', state: 'active' },
    { indicator: '4', labelTitle: 'Confirmation', labelDesc: 'Review', state: 'pending' }
  ]);

  useEffect(() => {
    if (containerRef.current) {
      new MonochromeEdge.Stepper(containerRef.current, {
        type: 'default',
        layout: 'vertical'
      });
    }
  }, []);

  return (
    <div
      ref={containerRef}
      className="stepper"
      data-type="default"
      data-layout="vertical"
      data-steps={JSON.stringify(steps)}
    />
  );
}

Vue

<template>
  <div
    ref="stepperRef"
    class="stepper"
    data-type="default"
    data-layout="vertical"
    :data-steps="JSON.stringify(steps)"
  />
</template>

<script setup>
import { ref, onMounted } from 'vue';

const stepperRef = ref(null);
const steps = ref([
  { indicator: '1', labelTitle: 'Account', labelDesc: 'Setup', state: 'completed' },
  { indicator: '2', labelTitle: 'Verification', labelDesc: 'Email', state: 'completed' },
  { indicator: '3', labelTitle: 'Preferences', labelDesc: 'Settings', state: 'active' },
  { indicator: '4', labelTitle: 'Confirmation', labelDesc: 'Review', state: 'pending' }
]);

onMounted(() => {
  if (stepperRef.value) {
    new MonochromeEdge.Stepper(stepperRef.value, {
      type: 'default',
      layout: 'vertical'
    });
  }
});
</script>

jQuery

// Initialize vertical stepper
const stepper = new MonochromeEdge.Stepper($('.stepper')[0], {
  type: 'default',
  layout: 'vertical'
});

// Navigate between steps
$('#nextBtn').on('click', function() {
  const currentIdx = stepper.steps.findIndex(s => s.state === 'active');
  if (currentIdx >= 0 && currentIdx < stepper.steps.length - 1) {
    stepper.updateStep(currentIdx, { state: 'completed' });
    stepper.updateStep(currentIdx + 1, { state: 'active' });
  }
});

Stepper (Snake / Dynamic Spacing)

<div class="stepper"
     data-type="default"
     data-layout="snake"
     data-steps='[
         {"indicator":"1","labelTitle":"Initialize","state":"completed","title":"Initialize Project","desc":"Set up the project structure and dependencies"},
         {"indicator":"2","labelTitle":"Configure","labelDesc":"Setup","state":"completed","title":"Configuration","desc":"Configure build tools and environment"},
         {"indicator":"3","labelTitle":"Build","state":"completed"},
         {"indicator":"4","labelTitle":"Test","state":"completed"},
         {"indicator":"5","labelTitle":"Deploy","state":"active","title":"Deployment","desc":"Deploy to production environment"},
         {"indicator":"6","labelTitle":"Monitor","state":"pending"},
         {"indicator":"7","labelTitle":"Optimize","state":"pending"},
         {"indicator":"8","labelTitle":"Finalize","state":"pending"}
     ]'>
</div>

React

import { useEffect, useRef } from 'react';

function SnakeStepperDemo() {
  const containerRef = useRef(null);

  useEffect(() => {
    if (containerRef.current) {
      const stepper = new MonochromeEdge.Stepper(containerRef.current, {
        type: 'default',
        layout: 'snake',
        onStepClick: (index) => console.log('Step:', index)
      });
    }
  }, []);

  const steps = [
    { indicator: '1', labelTitle: 'Initialize', state: 'completed' },
    { indicator: '2', labelTitle: 'Configure', state: 'completed' },
    { indicator: '3', labelTitle: 'Build', state: 'completed' },
    { indicator: '4', labelTitle: 'Test', state: 'completed' },
    { indicator: '5', labelTitle: 'Deploy', state: 'active' },
    { indicator: '6', labelTitle: 'Monitor', state: 'pending' }
  ];

  return (
    <div
      ref={containerRef}
      className="stepper"
      data-type="default"
      data-layout="snake"
      data-steps={JSON.stringify(steps)}
    />
  );
}

Vue

<template>
  <div
    ref="stepperRef"
    class="stepper"
    data-type="default"
    data-layout="snake"
    :data-steps="JSON.stringify(steps)"
  />
</template>

<script setup>
import { ref, onMounted } from 'vue';

const stepperRef = ref(null);
const steps = ref([
  { indicator: '1', labelTitle: 'Initialize', state: 'completed' },
  { indicator: '2', labelTitle: 'Configure', state: 'completed' },
  { indicator: '3', labelTitle: 'Build', state: 'completed' },
  { indicator: '4', labelTitle: 'Test', state: 'completed' },
  { indicator: '5', labelTitle: 'Deploy', state: 'active' },
  { indicator: '6', labelTitle: 'Monitor', state: 'pending' }
]);

onMounted(() => {
  if (stepperRef.value) {
    new MonochromeEdge.Stepper(stepperRef.value, {
      type: 'default',
      layout: 'snake'
    });
  }
});
</script>

jQuery

// Initialize snake stepper
const stepper = new MonochromeEdge.Stepper($('.stepper')[0], {
  type: 'default',
  layout: 'snake'
});

// Advance to next step
function advanceStep() {
  const activeIdx = stepper.steps.findIndex(s => s.state === 'active');
  if (activeIdx >= 0 && activeIdx < stepper.steps.length - 1) {
    stepper.updateStep(activeIdx, { state: 'completed' });
    stepper.updateStep(activeIdx + 1, { state: 'active' });
  }
}

Text Stepper (Horizontal)

<div class="stepper"
     data-type="text"
     data-layout="horizontal"
     data-steps='[
         {"labelTitle":"Personal Information","state":"completed"},
         {"labelTitle":"Shipping Address Details","state":"active"},
         {"labelTitle":"Payment Method","state":"pending"},
         {"labelTitle":"Order Confirmation","state":"pending"}
     ]'>
</div>

React

import { useEffect, useRef } from 'react';

function TextStepperDemo() {
  const containerRef = useRef(null);

  useEffect(() => {
    if (containerRef.current) {
      new MonochromeEdge.Stepper(containerRef.current, {
        type: 'text',
        layout: 'horizontal'
      });
    }
  }, []);

  const steps = [
    { labelTitle: 'Personal Info', state: 'completed' },
    { labelTitle: 'Address', state: 'active' },
    { labelTitle: 'Payment', state: 'pending' },
    { labelTitle: 'Confirm', state: 'pending' }
  ];

  return (
    <div
      ref={containerRef}
      className="stepper"
      data-type="text"
      data-layout="horizontal"
      data-steps={JSON.stringify(steps)}
    />
  );
}

Vue

<template>
  <div
    ref="stepperRef"
    class="stepper"
    data-type="text"
    data-layout="horizontal"
    :data-steps="JSON.stringify(steps)"
  />
</template>

<script setup>
import { ref, onMounted } from 'vue';

const stepperRef = ref(null);
const steps = ref([
  { labelTitle: 'Personal Info', state: 'completed' },
  { labelTitle: 'Address', state: 'active' },
  { labelTitle: 'Payment', state: 'pending' },
  { labelTitle: 'Confirm', state: 'pending' }
]);

onMounted(() => {
  if (stepperRef.value) {
    new MonochromeEdge.Stepper(stepperRef.value, {
      type: 'text',
      layout: 'horizontal'
    });
  }
});
</script>

jQuery

// Initialize text stepper
const stepper = new MonochromeEdge.Stepper($('.stepper')[0], {
  type: 'text',
  layout: 'horizontal'
});

Text Stepper (Vertical)

<div class="stepper"
     data-type="text"
     data-layout="vertical"
     data-steps='[
         {"labelTitle":"Setup","state":"completed","title":"Initial Setup","desc":"Configure basic settings"},
         {"labelTitle":"Connect","state":"active","title":"Connect Account","desc":"Link your account"},
         {"labelTitle":"Verify","state":"pending","title":"Verification","desc":"Verify your identity"},
         {"labelTitle":"Complete","state":"pending","title":"Completion","desc":"Finish setup"}
     ]'>
</div>

React

import { useEffect, useRef } from 'react';

function TextVerticalStepperDemo() {
  const containerRef = useRef(null);

  useEffect(() => {
    if (containerRef.current) {
      new MonochromeEdge.Stepper(containerRef.current, {
        type: 'text',
        layout: 'vertical'
      });
    }
  }, []);

  const steps = [
    { labelTitle: 'Setup', state: 'completed', title: 'Initial Setup', desc: 'Configure basic settings' },
    { labelTitle: 'Connect', state: 'active', title: 'Connect Account', desc: 'Link your account' },
    { labelTitle: 'Verify', state: 'pending', title: 'Verification', desc: 'Verify your identity' },
    { labelTitle: 'Complete', state: 'pending', title: 'Completion', desc: 'Finish setup' }
  ];

  return (
    <div
      ref={containerRef}
      className="stepper"
      data-type="text"
      data-layout="vertical"
      data-steps={JSON.stringify(steps)}
    />
  );
}

Vue

<template>
  <div
    ref="stepperRef"
    class="stepper"
    data-type="text"
    data-layout="vertical"
    :data-steps="JSON.stringify(steps)"
  />
</template>

<script setup>
import { ref, onMounted } from 'vue';

const stepperRef = ref(null);
const steps = ref([
  { labelTitle: 'Setup', state: 'completed', title: 'Initial Setup', desc: 'Configure basic settings' },
  { labelTitle: 'Connect', state: 'active', title: 'Connect Account', desc: 'Link your account' },
  { labelTitle: 'Verify', state: 'pending', title: 'Verification', desc: 'Verify your identity' },
  { labelTitle: 'Complete', state: 'pending', title: 'Completion', desc: 'Finish setup' }
]);

onMounted(() => {
  if (stepperRef.value) {
    new MonochromeEdge.Stepper(stepperRef.value, {
      type: 'text',
      layout: 'vertical'
    });
  }
});
</script>

jQuery

// Initialize text vertical stepper
const stepper = new MonochromeEdge.Stepper($('.stepper')[0], {
  type: 'text',
  layout: 'vertical'
});

Text Stepper (Snake)

<div class="stepper"
     data-type="text"
     data-layout="snake"
     data-steps='[
         {"labelTitle":"Plan","state":"completed"},
         {"labelTitle":"Design","state":"completed"},
         {"labelTitle":"Develop","state":"active"},
         {"labelTitle":"Test","state":"pending"},
         {"labelTitle":"Deploy","state":"pending"},
         {"labelTitle":"Monitor","state":"pending"}
     ]'>
</div>

React

import { useEffect, useRef } from 'react';

function TextSnakeStepperDemo() {
  const containerRef = useRef(null);

  useEffect(() => {
    if (containerRef.current) {
      new MonochromeEdge.Stepper(containerRef.current, {
        type: 'text',
        layout: 'snake'
      });
    }
  }, []);

  const steps = [
    { labelTitle: 'Plan', state: 'completed' },
    { labelTitle: 'Design', state: 'completed' },
    { labelTitle: 'Develop', state: 'active' },
    { labelTitle: 'Test', state: 'pending' },
    { labelTitle: 'Deploy', state: 'pending' },
    { labelTitle: 'Monitor', state: 'pending' }
  ];

  return (
    <div
      ref={containerRef}
      className="stepper"
      data-type="text"
      data-layout="snake"
      data-steps={JSON.stringify(steps)}
    />
  );
}

Vue

<template>
  <div
    ref="stepperRef"
    class="stepper"
    data-type="text"
    data-layout="snake"
    :data-steps="JSON.stringify(steps)"
  />
</template>

<script setup>
import { ref, onMounted } from 'vue';

const stepperRef = ref(null);
const steps = ref([
  { labelTitle: 'Plan', state: 'completed' },
  { labelTitle: 'Design', state: 'completed' },
  { labelTitle: 'Develop', state: 'active' },
  { labelTitle: 'Test', state: 'pending' },
  { labelTitle: 'Deploy', state: 'pending' },
  { labelTitle: 'Monitor', state: 'pending' }
]);

onMounted(() => {
  if (stepperRef.value) {
    new MonochromeEdge.Stepper(stepperRef.value, {
      type: 'text',
      layout: 'snake'
    });
  }
});
</script>

jQuery

// Initialize text snake stepper
const stepper = new MonochromeEdge.Stepper($('.stepper')[0], {
  type: 'text',
  layout: 'snake'
});

Tags & Badges CSS

Standardized tags and badges used throughout the UI library for categorization, status indication, and metadata display.

Component Type Tags

Individual Tags

CSS JS SVG CANVAS

Combined Tags (Section Headers)

CSS CSSJS SVGJS CANVASJS

HTML/CSS

<!-- Individual Tags -->
<span class="component-tag component-tag-css">CSS</span>
<span class="component-tag component-tag-js">JS</span>
<span class="component-tag component-tag-svg">SVG</span>
<span class="component-tag component-tag-canvas">CANVAS</span>

<!-- Combined Tags (for section headers) -->
<span class="component-tags">
    <span class="component-tag component-tag-css">CSS</span>
    <span class="component-tag component-tag-js">JS</span>
</span>

CSS Classes

/* Base Tag Styles */
.component-tag {
    display: inline-block;
    padding: 0.125rem 0.5rem;
    font-size: 0.625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-radius: calc(var(--border-radius) / 2);
    border: 1px solid var(--theme-border);
}

/* Type Variants */
.component-tag-css {
    background-color: var(--theme-bg);
    color: var(--theme-text-secondary);
}

.component-tag-js {
    background-color: var(--theme-accent);
    color: var(--theme-accent-contrast);
}

.component-tag-svg {
    background-color: var(--theme-surface);
    color: var(--theme-text-primary);
    border-color: var(--theme-accent);
}

.component-tag-canvas {
    background-color: var(--theme-accent);
    color: var(--theme-accent-contrast);
    opacity: 0.9;
}

/* Container for multiple tags */
.component-tags {
    display: inline-flex;
    gap: 0.375rem;
    align-items: center;
}

Status Badges

Semantic Colors

Success Warning Error Info

Sizes

Extra Small Small Medium (Default) Large

Outline Variants

Success Warning Error Info

HTML

<!-- Semantic Badges -->
<span class="badge badge-success">Success</span>
<span class="badge badge-warning">Warning</span>
<span class="badge badge-error">Error</span>
<span class="badge badge-info">Info</span>

<!-- Sizes -->
<span class="badge badge-xs">Extra Small</span>
<span class="badge badge-sm">Small</span>
<span class="badge">Medium</span>
<span class="badge badge-lg">Large</span>

<!-- Outline Variants -->
<span class="badge badge-outline badge-success">Success</span>
<span class="badge badge-outline badge-error">Error</span>

CSS (Add to your styles)

/* Base Badge */
.badge {
    display: inline-block;
    padding: 0.25rem 0.625rem;
    font-size: 0.75rem;
    font-weight: 600;
    border-radius: calc(var(--border-radius) * 0.75);
    background-color: var(--theme-surface);
    color: var(--theme-text-primary);
    border: 1px solid var(--theme-border);
}

/* Semantic Colors */
.badge-success {
    background-color: var(--color-success);
    color: white;
    border-color: var(--color-success);
}

.badge-warning {
    background-color: var(--color-warning);
    color: var(--theme-text-primary);
    border-color: var(--color-warning);
}

.badge-error {
    background-color: var(--color-error);
    color: white;
    border-color: var(--color-error);
}

.badge-info {
    background-color: var(--color-info);
    color: white;
    border-color: var(--color-info);
}

/* Sizes */
.badge-xs {
    padding: 0.125rem 0.375rem;
    font-size: 0.625rem;
}
.badge-sm {
    padding: 0.1875rem 0.5rem;
    font-size: 0.6875rem;
}
.badge-lg {
    padding: 0.375rem 0.875rem;
    font-size: 0.875rem;
}

/* Outline Variant */
.badge-outline {
    background-color: transparent;
}

.badge-outline.badge-success {
    color: var(--color-success);
}

.badge-outline.badge-warning {
    color: var(--color-warning);
}

.badge-outline.badge-error {
    color: var(--color-error);
}

.badge-outline.badge-info {
    color: var(--color-info);
}

Usage in Context

Component Name CSS JS

Use component-tag for showing tech stack/type in docs

Task Item

Completed

Use badge for showing status, notifications, counts

React TypeScript • 5 min read

Use badge-outline for categories, tags, filters

Pending Secondary information

Badge: Interactive or semantic status | Text/Small: Descriptive or static text

<!-- 1. Component Tags (for documentation) -->
<!-- Use component-tag for showing tech stack/type in docs -->
<h2>
    Component Name
    <span class="component-tags">
        <span class="component-tag component-tag-css">CSS</span>
        <span class="component-tag component-tag-js">JS</span>
    </span>
</h2>

<!-- 2. Status Badge (for UI state) -->
<!-- Use badge for showing status, notifications, counts -->
<div class="card">
    <div style="display: flex; justify-content: space-between;">
        <h4>Task Item</h4>
        <span class="badge badge-success">Completed</span>
    </div>
</div>

<!-- 3. Metadata Tags (for categories/labels) -->
<!-- Use badge-outline for categories, tags, filters -->
<div style="display: flex; gap: 0.5rem; align-items: center;">
    <span class="badge badge-xs badge-outline badge-info">React</span>
    <span class="badge badge-xs badge-outline badge-info">TypeScript</span>
    <small class="text-muted">• 5 min read</small>
</div>

<!-- 4. Badge vs Text -->
<!-- Badge: Interactive or semantic status -->
<span class="badge badge-warning">Pending</span>

<!-- Text/Small: Descriptive or static text -->
<small class="text-muted">Secondary information</small>

Accordion CSSJS

Expandable content panels for organizing information hierarchically.

Accordion Types

Monochrome Edge is a minimalist UI component library designed for modern web applications with a focus on clean aesthetics and usability.
Simply import the CSS file and start using the components in your HTML. Check the documentation for detailed examples.
Yes, all components are fully responsive and work seamlessly across desktop, tablet, and mobile devices.

HTML/CSS

<div class="accordion">
    <div class="accordion-item">
        <div class="accordion-header">
            <button class="accordion-button">
                <span>Question Title</span>
                <span class="accordion-icon">▼</span>
            </button>
        </div>
        <div class="accordion-collapse">
            <div class="accordion-body">
                Answer content goes here.
            </div>
        </div>
    </div>
</div>

<script>
// Toggle accordion
$('.accordion-button').on('click', function() {
    $(this).toggleClass('active');
    $(this).closest('.accordion-item')
        .find('.accordion-collapse')
        .toggleClass('show');
});
</script>

React

import { Accordion } from '@monochrome-edge/react';

function FAQ() {
  const items = [
    { id: '1', title: 'What is Monochrome Edge?', content: 'A minimalist UI library...' },
    { id: '2', title: 'How to get started?', content: 'Install via npm...' },
    { id: '3', title: 'Is it responsive?', content: 'Yes, fully responsive.' }
  ];

  return (
    <Accordion
      items={items}
      defaultExpandedIds={['1']}
      allowMultiple={false}
      onChange={(expandedIds) => console.log(expandedIds)}
    />
  );
}

Vue

<template>
  <Accordion
    :items="items"
    :default-expanded-ids="['1']"
    :allow-multiple="false"
    @change="handleChange"
  />
</template>

<script setup>
import { Accordion } from '@monochrome-edge/vue';

const items = [
  { id: '1', title: 'What is Monochrome Edge?', content: 'A minimalist UI library...' },
  { id: '2', title: 'How to get started?', content: 'Install via npm...' },
  { id: '3', title: 'Is it responsive?', content: 'Yes, fully responsive.' }
];

const handleChange = (expandedIds) => {
  console.log('Expanded:', expandedIds);
};
</script>

Web Components

<mce-accordion id="faq" allow-multiple="false">
  <div data-accordion-id="1" data-accordion-title="What is Monochrome Edge?">
    A minimalist UI library...
  </div>
  <div data-accordion-id="2" data-accordion-title="How to get started?">
    Install via npm...
  </div>
</mce-accordion>

<script type="module">
  import '@monochrome-edge/web-components';

  document.getElementById('faq').addEventListener('change', (e) => {
    console.log('Expanded:', e.detail.expandedIds);
  });
</script>

jQuery

$('#accordion-container').accordion({
  allowMultiple: false,
  defaultExpandedIds: ['1'],
  onChange: (expandedIds) => {
    console.log('Expanded:', expandedIds);
  }
});

// HTML structure
<div id="accordion-container">
  <div data-accordion-id="1" data-accordion-title="What is Monochrome Edge?">
    A minimalist UI library...
  </div>
  <div data-accordion-id="2" data-accordion-title="How to get started?">
    Install via npm...
  </div>
</div>

Callout CSS

Alert and notification components with semantic color variants.

Callout Variants

Info

This is an informational callout with important details about the feature.

Success

Your changes have been saved successfully!

Warning

Please review your settings before proceeding.

Error

An error occurred while processing your request.

<!-- Info Callout -->
<div class="callout callout-info">
    <div class="callout-icon">
        <!-- Icon SVG -->
    </div>
    <div class="callout-content">
        <div class="callout-title">Info</div>
        <p>Informational message here.</p>
    </div>
</div>

<!-- Success Callout -->
<div class="callout callout-success">
    <div class="callout-icon">
        <!-- Icon SVG -->
    </div>
    <div class="callout-content">
        <div class="callout-title">Success</div>
        <p>Success message here.</p>
    </div>
</div>

<!-- Warning Callout -->
<div class="callout callout-warning">
    <div class="callout-icon">
        <!-- Icon SVG -->
    </div>
    <div class="callout-content">
        <div class="callout-title">Warning</div>
        <p>Warning message here.</p>
    </div>
</div>

<!-- Error Callout -->
<div class="callout callout-error">
    <div class="callout-icon">
        <!-- Icon SVG -->
    </div>
    <div class="callout-content">
        <div class="callout-title">Error</div>
        <p>Error message here.</p>
    </div>
</div>

Component Examples

Real-world examples of Monochrome components in different frameworks.

Button Component

import React from 'react';
import { Button } from '@monochrome-edge';  // TSX components from main package

function App() {
  return (
    <div>
      <Button variant="primary" size="large">
        Primary Button
      </Button>
      <Button variant="secondary" loading>
        Loading...
      </Button>
      <Button variant="ghost" onClick={() => alert('Clicked!')}>
        Ghost Button
      </Button>
    </div>
  );
}
<template>
  <div>
    <mce-button variant="primary" size="large">
      Primary Button
    </mce-button>
    <mce-button variant="secondary" :loading="true">
      Loading...
    </mce-button>
    <mce-button variant="ghost" @click="handleClick">
      Ghost Button
    </mce-button>
  </div>
</template>

<script setup lang="ts">
import { MonochromeButton } from '@monochrome-edge/vue';

const handleClick = () => {
  alert('Clicked!');
};
</script>
import { MonochromeComponents } from '@monochrome-edge/vanilla';

// Create buttons
const primaryBtn = MonochromeComponents.button('Primary Button', {
  variant: 'primary',
  size: 'large'
});

const loadingBtn = MonochromeComponents.button('Loading...', {
  variant: 'secondary',
  loading: true
});

const ghostBtn = MonochromeComponents.button('Ghost Button', {
  variant: 'ghost',
  onClick: (e) => alert('Clicked!')
});

// Append to container
const container = document.getElementById('button-container');
container.appendChild(primaryBtn);
container.appendChild(loadingBtn);
container.appendChild(ghostBtn);
// Initialize buttons with jQuery
$('#primary-btn').monochromeButton({
  variant: 'primary',
  size: 'large'
});

$('#loading-btn').monochromeButton({
  variant: 'secondary',
  loading: true
});

$('#ghost-btn').monochromeButton({
  variant: 'ghost'
}).on('click', function() {
  alert('Clicked!');
});

// Or create dynamically
$('<button>Dynamic Button</button>')
  .monochromeButton({ variant: 'primary' })
  .appendTo('#container');
<!-- Import Web Components first -->
<script type="module">
  import '@monochrome-edge/wc';
</script>

<!-- Use as custom elements -->
<mce-button variant="primary" size="large">
  Primary Button
</mce-button>

<mce-button variant="secondary" loading="true">
  Loading...
</mce-button>

<mce-button variant="ghost" id="ghost-btn">
  Ghost Button
</mce-button>

<script>
  // Add event listener
  document.getElementById('ghost-btn')
    .addEventListener('click', () => alert('Clicked!'));

  // Or create dynamically
  const btn = document.createElement('monochrome-button');
  btn.setAttribute('variant', 'primary');
  btn.textContent = 'Dynamic Button';
  document.body.appendChild(btn);
</script>

Form Component

import React, { useState } from 'react';
import { FormGroup, Label, Input, Button } from '@monochrome-edge';  // TSX components

function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  return (
    <form onSubmit={(e) => e.preventDefault()}>
      <FormGroup>
        <Label htmlFor="email" required>Email</Label>
        <Input
          id="email"
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          placeholder="you@example.com"
        />
      </FormGroup>

      <FormGroup>
        <Label htmlFor="password" required>Password</Label>
        <Input
          id="password"
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
      </FormGroup>

      <Button type="submit" variant="primary">
        Sign In
      </Button>
    </form>
  );
}
<template>
  <form @submit.prevent="handleSubmit">
    <form-group>
      <form-label for="email" required>Email</form-label>
      <form-input
        id="email"
        type="email"
        v-model="email"
        placeholder="you@example.com"
      />
    </form-group>

    <form-group>
      <form-label for="password" required>Password</form-label>
      <form-input
        id="password"
        type="password"
        v-model="password"
      />
    </form-group>

    <mce-button type="submit" variant="primary">
      Sign In
    </mce-button>
  </form>
</template>

<script setup>
import { ref } from 'vue';

const email = ref('');
const password = ref('');

const handleSubmit = () => {
  console.log('Login:', email.value, password.value);
};
</script>
import { MonochromeComponents } from '@monochrome-edge/vanilla';

// Create form elements
const emailInput = MonochromeComponents.input({
  type: 'email',
  placeholder: 'you@example.com',
  onChange: (value) => console.log('Email:', value)
});

const passwordInput = MonochromeComponents.input({
  type: 'password',
  onChange: (value) => console.log('Password:', value)
});

const emailGroup = MonochromeComponents.formGroup(
  'Email',
  emailInput,
  { required: true }
);

const passwordGroup = MonochromeComponents.formGroup(
  'Password',
  passwordInput,
  { required: true }
);

const submitBtn = MonochromeComponents.button('Sign In', {
  variant: 'primary',
  onClick: () => {
    console.log('Form submitted');
  }
});

// Create form
const form = document.createElement('form');
form.appendChild(emailGroup);
form.appendChild(passwordGroup);
form.appendChild(submitBtn);

document.getElementById('form-container').appendChild(form);
// Enhance existing form
$('#login-form').monochromeForm();

// Handle form submission
$('#login-form').on('submit', function(e) {
  e.preventDefault();

  const formData = {
    email: $('#email').val(),
    password: $('#password').val()
  };

  console.log('Login:', formData);
});

// Add validation
$('#email').on('blur', function() {
  const $input = $(this);
  if (!$input.val().includes('@')) {
    $input.addClass('is-error');
    $input.after('<span class="helper-text error">Invalid email</span>');
  } else {
    $input.removeClass('is-error');
    $input.next('.helper-text').remove();
  }
});
<form id="login-form">
  <div class="form-group">
    <label class="label" for="email">
      Email <span class="text-danger">*</span>
    </label>
    <input
      type="email"
      id="email"
      class="input"
      placeholder="you@example.com"
      required
    >
  </div>

  <div class="form-group">
    <label class="label" for="password">
      Password <span class="text-danger">*</span>
    </label>
    <input
      type="password"
      id="password"
      class="input"
      required
    >
  </div>

  <mce-button type="submit" variant="primary">
    Sign In
  </mce-button>
</form>

<script>
  document.getElementById('login-form')
    .addEventListener('submit', (e) => {
      e.preventDefault();
      const formData = new FormData(e.target);
      console.log('Login:', Object.fromEntries(formData));
    });
</script>

Card Component

import React from 'react';
import { Card, CardHeader, CardBody, StatCard } from '@monochrome-edge';

function DashboardCards() {
  return (
    <div className="grid grid-cols-3 gap-4">
      {/* Basic Card */}
      <Card>
        <CardHeader>
          <h3>Basic Card</h3>
        </CardHeader>
        <CardBody>
          <p>This is a basic card with header and body.</p>
        </CardBody>
      </Card>

      {/* Stat Card */}
      <StatCard
        title="Total Revenue"
        value="$12,426"
        change="+12.5%"
        trend="up"
        period="from last month"
      />

      {/* Custom Styled Card */}
      <Card className="border-highlight">
        <CardBody>
          <div className="flex items-center justify-between">
            <span className="text-secondary">Active Users</span>
            <span className="text-2xl font-bold">1,234</span>
          </div>
        </CardBody>
      </Card>
    </div>
  );
}
<template>
  <div class="grid grid-cols-3 gap-4">
    <!-- Basic Card -->
    <mce-card>
      <template #header>
        <h3>Basic Card</h3>
      </template>
      <p>This is a basic card with header and body.</p>
    </mce-card>

    <!-- Stat Card -->
    <stat-card
      title="Total Revenue"
      value="$12,426"
      change="+12.5%"
      trend="up"
      period="from last month"
    />

    <!-- Custom Styled Card -->
    <mce-card class="border-highlight">
      <div class="flex items-center justify-between">
        <span class="text-secondary">Active Users</span>
        <span class="text-2xl font-bold">1,234</span>
      </div>
    </mce-card>
  </div>
</template>

<script setup>
import { MonoCard, StatCard } from '@monochrome-edge/vue';
</script>
import { MonochromeComponents } from '@monochrome-edge/vanilla';

// Create basic card
const basicCard = MonochromeComponents.card({
  title: 'Basic Card',
  content: 'This is a basic card with header and body.'
});

// Create stat card
const statCard = MonochromeComponents.statCard({
  title: 'Total Revenue',
  value: '$12,426',
  change: '+12.5%',
  trend: 'up',
  period: 'from last month'
});

// Create custom card
const customCard = document.createElement('div');
customCard.className = 'card border-highlight';
customCard.innerHTML = `
  <div class="card-body">
    <div class="flex items-center justify-between">
      <span class="text-secondary">Active Users</span>
      <span class="text-2xl font-bold">1,234</span>
    </div>
  </div>
`;

// Append to container
const container = document.getElementById('card-container');
container.appendChild(basicCard);
container.appendChild(statCard);
container.appendChild(customCard);
// Create cards with jQuery
const cards = [
  {
    type: 'basic',
    title: 'Basic Card',
    content: 'This is a basic card with header and body.'
  },
  {
    type: 'stat',
    title: 'Total Revenue',
    value: '$12,426',
    change: '+12.5%',
    trend: 'up'
  }
];

// Initialize cards
cards.forEach(card => {
  if (card.type === 'basic') {
    const $card = $('<div class="card"></div>');
    $card.append(`
      <div class="card-header">${card.title}</div>
      <div class="card-body">${card.content}</div>
    `);
    $('#card-container').append($card);
  } else if (card.type === 'stat') {
    const $statCard = $('<div class="stat-card"></div>');
    $statCard.html(`
      <h4 class="stat-title">${card.title}</h4>
      <div class="stat-value">${card.value}</div>
      <div class="stat-change ${card.trend}">${card.change}</div>
    `);
    $('#card-container').append($statCard);
  }
});
<!-- Basic Card -->
<div class="card">
  <div class="card-header">
    <h3>Basic Card</h3>
  </div>
  <div class="card-body">
    <p>This is a basic card with header and body.</p>
  </div>
</div>

<!-- Stat Card -->
<div class="stat-card">
  <h4 class="stat-title">Total Revenue</h4>
  <div class="stat-value">$12,426</div>
  <div class="stat-change positive">
    <span class="arrow">↑</span> +12.5%
    <span class="period">from last month</span>
  </div>
</div>

<!-- Custom Card with Web Components -->
<mce-card title="Active Users">
  <div class="flex items-center justify-between">
    <span class="text-secondary">Current</span>
    <span class="text-2xl font-bold">1,234</span>
  </div>
</mce-card>

Modal Component

Table Component

import React, { useState } from 'react';
import { Table, TableHeader, TableBody, TableRow, TableCell } from '@monochrome-edge';

function DataTable() {
  const [data] = useState([
    { id: 1, name: 'John Doe', email: 'john@example.com', status: 'active' },
    { id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'inactive' },
    { id: 3, name: 'Bob Johnson', email: 'bob@example.com', status: 'active' },
  ]);

  return (
    <Table>
      <TableHeader>
        <TableRow>
          <TableCell header>Name</TableCell>
          <TableCell header>Email</TableCell>
          <TableCell header>Status</TableCell>
          <TableCell header>Actions</TableCell>
        </TableRow>
      </TableHeader>
      <TableBody>
        {data.map(row => (
          <TableRow key={row.id}>
            <TableCell>{row.name}</TableCell>
            <TableCell>{row.email}</TableCell>
            <TableCell>
              <span className={`badge badge-${row.status}`}>
                {row.status}
              </span>
            </TableCell>
            <TableCell>
              <button className="btn btn-sm btn-ghost">Edit</button>
              <button className="btn btn-sm btn-danger">Delete</button>
            </TableCell>
          </TableRow>
        ))}
      </TableBody>
    </Table>
  );
}
<template>
  <mce-table>
    <mce-table-header>
      <mce-table-row>
        <mce-table-cell header>Name</mce-table-cell>
        <mce-table-cell header>Email</mce-table-cell>
        <mce-table-cell header>Status</mce-table-cell>
        <mce-table-cell header>Actions</mce-table-cell>
      </mce-table-row>
    </mce-table-header>
    <mce-table-body>
      <mce-table-row v-for="row in data" :key="row.id">
        <mce-table-cell>{{ row.name }}</mce-table-cell>
        <mce-table-cell>{{ row.email }}</mce-table-cell>
        <mce-table-cell>
          <span :class="`badge badge-${row.status}`">
            {{ row.status }}
          </span>
        </mce-table-cell>
        <mce-table-cell>
          <button class="btn btn-sm btn-ghost" @click="editRow(row)">
            Edit
          </button>
          <button class="btn btn-sm btn-danger" @click="deleteRow(row)">
            Delete
          </button>
        </mce-table-cell>
      </mce-table-row>
    </mce-table-body>
  </mce-table>
</template>

<script setup>
import { ref } from 'vue';

const data = ref([
  { id: 1, name: 'John Doe', email: 'john@example.com', status: 'active' },
  { id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'inactive' },
  { id: 3, name: 'Bob Johnson', email: 'bob@example.com', status: 'active' },
]);

const editRow = (row) => console.log('Edit:', row);
const deleteRow = (row) => console.log('Delete:', row);
</script>
import { MonochromeComponents } from '@monochrome-edge/vanilla';

const data = [
  { id: 1, name: 'John Doe', email: 'john@example.com', status: 'active' },
  { id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'inactive' },
  { id: 3, name: 'Bob Johnson', email: 'bob@example.com', status: 'active' },
];

// Create table
const table = MonochromeComponents.table({
  columns: [
    { key: 'name', label: 'Name' },
    { key: 'email', label: 'Email' },
    {
      key: 'status',
      label: 'Status',
      render: (value) => {
        const badge = document.createElement('span');
        badge.className = `badge badge-${value}`;
        badge.textContent = value;
        return badge;
      }
    },
    {
      key: 'actions',
      label: 'Actions',
      render: (_, row) => {
        const container = document.createElement('div');

        const editBtn = document.createElement('button');
        editBtn.className = 'btn btn-sm btn-ghost';
        editBtn.textContent = 'Edit';
        editBtn.onclick = () => console.log('Edit:', row);

        const deleteBtn = document.createElement('button');
        deleteBtn.className = 'btn btn-sm btn-danger';
        deleteBtn.textContent = 'Delete';
        deleteBtn.onclick = () => console.log('Delete:', row);

        container.appendChild(editBtn);
        container.appendChild(deleteBtn);
        return container;
      }
    }
  ],
  data: data,
  sortable: true,
  filterable: true
});

document.getElementById('table-container').appendChild(table);
// Initialize data table with jQuery
const data = [
  { id: 1, name: 'John Doe', email: 'john@example.com', status: 'active' },
  { id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'inactive' },
  { id: 3, name: 'Bob Johnson', email: 'bob@example.com', status: 'active' },
];

// Create table HTML
const tableHtml = `
  <table class="table" id="data-table">
    <thead>
      <tr>
        <th>Name</th>
        <th>Email</th>
        <th>Status</th>
        <th>Actions</th>
      </tr>
    </thead>
    <tbody></tbody>
  </table>
`;

$('#table-container').html(tableHtml);

// Populate table
data.forEach(row => {
  const $row = $('<tr></tr>');
  $row.append(`<td>${row.name}</td>`);
  $row.append(`<td>${row.email}</td>`);
  $row.append(`<td><span class="badge badge-${row.status}">${row.status}</span></td>`);
  $row.append(`
    <td>
      <button class="btn btn-sm btn-ghost edit-btn" data-id="${row.id}">Edit</button>
      <button class="btn btn-sm btn-danger delete-btn" data-id="${row.id}">Delete</button>
    </td>
  `);
  $('#data-table tbody').append($row);
});

// Event handlers
$(document).on('click', '.edit-btn', function() {
  const id = $(this).data('id');
  console.log('Edit row:', id);
});

$(document).on('click', '.delete-btn', function() {
  const id = $(this).data('id');
  if (confirm('Delete this row?')) {
    $(this).closest('tr').fadeOut(() => {
      $(this).remove();
    });
  }
});
<table class="table">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th>Status</th>
      <th>Actions</th>
    </tr>
  </thead>
  <tbody id="table-body"></tbody>
</table>

<script>
// Data
const data = [
  { id: 1, name: 'John Doe', email: 'john@example.com', status: 'active' },
  { id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'inactive' },
  { id: 3, name: 'Bob Johnson', email: 'bob@example.com', status: 'active' },
];

// Render table rows
const tbody = document.getElementById('table-body');

data.forEach(row => {
  const tr = document.createElement('tr');

  // Name cell
  const nameCell = document.createElement('td');
  nameCell.textContent = row.name;
  tr.appendChild(nameCell);

  // Email cell
  const emailCell = document.createElement('td');
  emailCell.textContent = row.email;
  tr.appendChild(emailCell);

  // Status cell
  const statusCell = document.createElement('td');
  const badge = document.createElement('span');
  badge.className = `badge badge-${row.status}`;
  badge.textContent = row.status;
  statusCell.appendChild(badge);
  tr.appendChild(statusCell);

  // Actions cell
  const actionsCell = document.createElement('td');

  const editBtn = document.createElement('button');
  editBtn.className = 'btn btn-sm btn-ghost';
  editBtn.textContent = 'Edit';
  editBtn.onclick = () => console.log('Edit:', row);

  const deleteBtn = document.createElement('button');
  deleteBtn.className = 'btn btn-sm btn-danger';
  deleteBtn.textContent = 'Delete';
  deleteBtn.onclick = () => {
    if (confirm('Delete this row?')) {
      tr.remove();
    }
  };

  actionsCell.appendChild(editBtn);
  actionsCell.appendChild(deleteBtn);
  tr.appendChild(actionsCell);

  tbody.appendChild(tr);
});
</script>

Navigation Component

Select Component

Editor CSSJS

Interactive code editor with live preview and theme customization.

Try the Live Editor

Edit HTML and CSS in real-time with instant preview. Perfect for testing components.

Open Editor →

Integration Guide

Learn how to install and use Monochrome Edge in your project with CDN or npm.

Get Started in Minutes

Comprehensive installation guide with CDN, npm, and framework examples.

View Integration Guide →

Section

Blog and portfolio section containers for organizing content with headings, subtitles, and dividers.

Blog Section

Recent Articles

Thoughts on design, development, and everything in between


This is a blog section component that provides structured content layout with clear hierarchy and spacing. Use it to organize your blog posts, articles, or any content that requires clean sectioning.

HTML/CSS

<section class="blog-section">
    <div class="blog-section-header">
        <h2 class="blog-section-title">Recent Articles</h2>
        <p class="blog-section-subtitle">
            Thoughts on design, development, and everything in between
        </p>
    </div>
    <hr class="blog-section-divider" />
    <div class="blog-content">
        <!-- Section content -->
    </div>
</section>

React

import React from 'react';
import { BlogSection } from '@monochrome-edge';

function BlogPage() {
  return (
    <BlogSection
      title="Recent Articles"
      subtitle="Thoughts on design, development, and everything in between"
    >
      <div className="blog-content">
        <p>Your blog content goes here...</p>
      </div>
    </BlogSection>
  );
}

Vue.js

<template>
  <blog-section
    title="Recent Articles"
    subtitle="Thoughts on design, development, and everything in between"
  >
    <div class="blog-content">
      <p>Your blog content goes here...</p>
    </div>
  </blog-section>
</template>

<script setup lang="ts">
import { BlogSection } from '@monochrome-edge/vue';
</script>

Article

Article and project card components for showcasing blog posts, portfolio items, and case studies.

Article Card

Design Systems

Building Modern UI Components

A comprehensive guide to creating reusable, theme-aware components with CSS variables.

Oct 7, 2025
CSS Design
Frontend

CSS Variables for Theming

Deep dive into using custom properties for dynamic, flexible design systems.

Oct 1, 2025
CSS

HTML/CSS

<article class="article-card">
    <div class="article-card-image article-card-image-grayscale">
        <img src="..." alt="Article thumbnail" />
    </div>
    <div class="article-card-content">
        <span class="article-card-category">Design Systems</span>
        <h3 class="article-card-title">Building Modern UI Components</h3>
        <p class="article-card-description">
            A comprehensive guide to creating reusable components...
        </p>
        <div class="article-card-meta">
            <span class="article-card-date">Oct 7, 2025</span>
            <div class="article-card-tags">
                <span class="article-card-tag">CSS</span>
                <span class="article-card-tag">Design</span>
            </div>
        </div>
    </div>
</article>

React

import React from 'react';
import { ArticleCard } from '@monochrome-edge';

function BlogGrid() {
  return (
    <div className="article-card-grid">
      <ArticleCard
        category="Design Systems"
        title="Building Modern UI Components"
        description="A comprehensive guide to creating reusable components..."
        date="Oct 7, 2025"
        tags={['CSS', 'Design']}
        image="/path/to/image.jpg"
        grayscale
      />
    </div>
  );
}

Vue.js

<template>
  <div class="article-card-grid">
    <article-card
      category="Design Systems"
      title="Building Modern UI Components"
      description="A comprehensive guide to creating reusable components..."
      date="Oct 7, 2025"
      :tags="['CSS', 'Design']"
      image="/path/to/image.jpg"
      grayscale
    />
  </div>
</template>

<script setup lang="ts">
import { ArticleCard } from '@monochrome-edge/vue';
</script>

Article List

HTML/CSS

<ul class="article-list">
    <li class="article-list-item">
        <a href="#" class="article-list-link">
            <span class="article-list-date">Oct 7, 2025</span>
            <h4 class="article-list-title">Building a Dual-Theme Design System</h4>
            <p class="article-list-excerpt">
                Exploring the challenges and solutions...
            </p>
            <div class="article-card-tags">
                <span class="article-card-tag">Design</span>
                <span class="article-card-tag">CSS</span>
            </div>
        </a>
    </li>
</ul>

React

import React from 'react';
import { ArticleList } from '@monochrome-edge';

function RecentPosts() {
  return (
    <ArticleList compact>
      <ArticleList.Item
        date="Oct 7, 2025"
        title="Understanding Design Systems"
        excerpt="Exploring the challenges and solutions..."
        tags={['Design', 'CSS']}
        href="/posts/design-systems"
      />
    </ArticleList>
  );
}

Vue.js

<template>
  <article-list compact>
    <article-list-item
      date="Oct 7, 2025"
      title="Understanding Design Systems"
      excerpt="Exploring the challenges and solutions..."
      :tags="['Design', 'CSS']"
      href="/posts/design-systems"
    />
  </article-list>
</template>

<script setup lang="ts">
import { ArticleList, ArticleListItem } from '@monochrome-edge/vue';
</script>

Project Card

Monochrome Edge

Active

Modern minimalist UI component library with dual-theme system.

1.2k
230
CSS Design System TypeScript
<article class="project-card">
    <div class="project-card-image project-card-image-grayscale">
        <img src="..." alt="Project thumbnail" />
    </div>
    <div class="project-card-content">
        <div class="project-card-header">
            <h3 class="project-card-title">Monochrome Edge</h3>
            <span class="project-card-status project-card-status-active">Active</span>
        </div>
        <p class="project-card-description">
            Modern minimalist UI component library...
        </p>
        <div class="project-card-stats">
            <div class="project-card-stat">
                <svg class="project-card-stat-icon">...</svg>
                <span class="project-card-stat-value">1.2k</span>
            </div>
        </div>
        <div class="project-card-tags">
            <span class="project-card-tag">CSS</span>
            <span class="project-card-tag">TypeScript</span>
        </div>
    </div>
</article>

Changelog

Track all notable changes to Monochrome Edge UI Components.

v1.13.14 2025-10-13

Documentation

  • docs: improve index.html demo page UX and content organization d62d9c6

v1.13.13 2025-10-13

Build

  • build: configure TypeScript compilation to separate .ts into .js and .d.ts for CDN deployment 8cf1aa6

v1.13.5 2025-10-12

Bug Fixes

  • fix: restore layout and component functionality c6d7e8f
  • fix: improve SVG icon loading for external projects 164f66c
  • fix: improve SVG icon loading for external projects 936188d

Chore

  • chore: bump version to 1.13.4 [skip ci] ed4e53e