A comprehensive, accessible web components library built with modern web standards
π Documentation β’ π Live Examples β’ π¬ Community
- π¦ 22+ Production-Ready Components - From buttons to complex carousels
- βΏ Accessibility First - ARIA attributes and keyboard navigation built-in
- π¨ Tailwind CSS Integration - Beautiful, customizable styling out of the box
- β‘ Alpine.js Powered - Reactive components with minimal JavaScript
- π± Responsive Design - Mobile-first approach for all screen sizes
- π§ Framework Agnostic - Works with React, Vue, Angular, or vanilla HTML
- π§ͺ 100% Test Coverage - Comprehensive test suite with Mocha
- π TypeScript Definitions - Full type support for better DX
- π Modern Browser Support - ES6+ with graceful degradation
# npm
npm install dry2-web-components
# yarn
yarn add dry2-web-components
# pnpm
pnpm add dry2-web-components
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DRY2 Example</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Alpine.js -->
<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>
</head>
<body>
<!-- DRY2 Components -->
<script type="module">
import 'dry2-web-components/src/dry2/dry2.js';
import 'dry2-web-components/src/dry2/button.js';
import 'dry2-web-components/src/dry2/avatar.js';
import 'dry2-web-components/src/dry2/toast.js';
</script>
<!-- Use the components -->
<div class="container mx-auto p-6">
<h1 class="text-3xl font-bold mb-6">Welcome to DRY2!</h1>
<div class="space-y-4">
<dry-button variant="primary" size="lg">
Get Started
</dry-button>
<avatar-component
name="John Doe"
src="https://example.com/avatar.jpg"
size="lg">
</avatar-component>
</div>
</div>
<script>
// Use the Toast API
document.querySelector('dry-button').addEventListener('click', () => {
Toast.success('Welcome to DRY2 Web Components!');
});
</script>
</body>
</html>
<dry-button>
- Versatile button with variants, sizes, loading states, and Font Awesome icons<toggle-switch>
- Accessible toggle switch for boolean inputs<super-select-component>
- Advanced select with search and multi-selection
<avatar-component>
- User avatars with image fallbacks and initials<badge-component>
- Status indicators and notification badges<card-component>
- Flexible content containers<stat-component>
- Statistical data display with trends
<breadcrumbs-component>
- Hierarchical navigation breadcrumbs<tabs-component>
- Tabbed interface with multiple variants
<dry-accordion>
- Collapsible content sections<collapse-component>
- Smooth height-based collapse animations<drawer-component>
- Side panel/drawer with HTMX support
<carousel-component>
- Touch-enabled carousel with autoplay<swap-component>
- Icon/state swapping with transitions<countdown-component>
- Flexible countdown timers
<chat-bubble>
- Chat message bubbles with status indicators<toast-component>
- Notification toasts with global API<dialog-component>
- Modal dialogs with HTMX integration
<timeline-component>
- Event timelines with custom styling<qr-component>
- QR code generation with customization
<dry-code>
- Syntax-highlighted code blocks with copy-to-clipboard functionality<wysiwyg-component>
- Rich text editor with HTML sanitization
DRY2 components are built with Tailwind CSS and support extensive customization:
<!-- Custom button styling -->
<dry-button
variant="primary"
size="lg"
class="shadow-xl hover:shadow-2xl transform hover:scale-105">
Custom Styled Button
</dry-button>
<!-- Button with Font Awesome icon -->
<dry-button
variant="primary"
icon="fas fa-plus">
Add Item
</dry-button>
<!-- Icon-only button -->
<dry-button
variant="outline"
icon="fas fa-download">
</dry-button>
<!-- Custom avatar colors -->
<avatar-component
name="Jane Doe"
style="--avatar-bg: #8b5cf6; --avatar-text: white;">
</avatar-component>
Many components support CSS custom properties for deep customization:
:root {
--dry-primary-color: #6366f1;
--dry-secondary-color: #64748b;
--dry-success-color: #10b981;
--dry-warning-color: #f59e0b;
--dry-error-color: #ef4444;
--dry-border-radius: 0.5rem;
--dry-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
DRY2 comes with comprehensive test coverage using Mocha and Chai:
# Run all tests
npm test
# Run tests with coverage
npm run test:coverage
# Run tests in watch mode
npm run test:watch
# Run tests for specific component
npm run test:component button
Example test for a custom component:
import { expect } from 'chai';
import '../setup.js';
describe('My Custom Component', () => {
let element;
beforeEach(() => {
element = document.createElement('my-component');
document.body.appendChild(element);
});
it('should create element', async () => {
await waitForComponent(element);
expect(element).to.exist;
});
it('should respond to attribute changes', async () => {
element.setAttribute('variant', 'primary');
await waitForComponent(element);
const button = element.querySelector('.button');
expect(button.className).to.include('bg-blue-600');
});
});
You can create custom components by extending HTMLElement:
class MyComponent extends HTMLElement {
static get observedAttributes() {
return ['variant', 'size', 'disabled'];
}
render() {
return `
<div class="${this.getComponentClasses()}">
${this.renderSlot('default', 'Default content')}
</div>
`;
}
getComponentClasses() {
return `component ${this.variant} ${this.size}`;
}
}
// Reactive state
this.setState({ loading: true });
// Listen to state changes automatically triggers re-render
// Emit custom events
this.emit('component:change', { value: newValue });
// Listen to events
element.addEventListener('component:change', (event) => {
console.log('New value:', event.detail.value);
});
// Built-in accessibility helpers
this.setAttribute('aria-label', 'Button description');
this.setAttribute('role', 'button');
this.setAttribute('tabindex', '0');
import { useEffect, useRef } from 'react';
import 'dry2-web-components/button';
function MyReactComponent() {
const buttonRef = useRef();
useEffect(() => {
const button = buttonRef.current;
const handleClick = (event) => {
console.log('Button clicked:', event.detail);
};
button.addEventListener('button:click', handleClick);
return () => button.removeEventListener('button:click', handleClick);
}, []);
return (
<dry-button
ref={buttonRef}
variant="primary"
size="lg">
React Button
</dry-button>
);
}
<template>
<dry-button
:variant="variant"
:size="size"
@button:click="handleClick">
Vue Button
</dry-button>
</template>
<script>
import 'dry2-web-components/button';
export default {
data() {
return {
variant: 'primary',
size: 'lg'
};
},
methods: {
handleClick(event) {
console.log('Button clicked:', event.detail);
}
}
};
</script>
import { Component, ElementRef, ViewChild } from '@angular/core';
import 'dry2-web-components/button';
@Component({
selector: 'app-button',
template: `
<dry-button
#buttonElement
[attr.variant]="variant"
[attr.size]="size"
(button:click)="handleClick($event)">
Angular Button
</dry-button>
`
})
export class ButtonComponent {
@ViewChild('buttonElement') buttonElement!: ElementRef;
variant = 'primary';
size = 'lg';
handleClick(event: CustomEvent) {
console.log('Button clicked:', event.detail);
}
}
All components are mobile-first and responsive:
<!-- Responsive button sizes -->
<dry-button
size="sm"
class="md:size-md lg:size-lg">
Responsive Button
</dry-button>
<!-- Responsive avatar -->
<avatar-component
size="sm"
class="md:size-md lg:size-lg"
name="John Doe">
</avatar-component>
Component | Gzipped Size | Dependencies |
---|---|---|
Base | 2.1 KB | None |
Button | 1.8 KB | Alpine.js |
Avatar | 1.5 KB | Alpine.js |
Toast | 2.3 KB | None |
Carousel | 3.2 KB | Alpine.js |
// Load components on demand
const loadButton = () => import('dry2-web-components/button');
const loadCarousel = () => import('dry2-web-components/carousel');
// Load when needed
if (needsCarousel) {
await loadCarousel();
}
Browser | Version | Support |
---|---|---|
Chrome | 73+ | β Full |
Firefox | 63+ | β Full |
Safari | 12.1+ | β Full |
Edge | 79+ | β Full |
For older browsers, include these polyfills:
<script src="https://unpkg.com/@webcomponents/webcomponentsjs@2/webcomponents-loader.js"></script>
<script src="https://unpkg.com/[email protected]/proxy.min.js"></script>
We welcome contributions! Please see our Contributing Guide for details.
# Clone the repository
git clone https://github.com/yourusername/dry2-web-components.git
cd dry2-web-components
# Install dependencies
npm install
# Start development server
npm run dev
# Run tests
npm test
# Build for production
npm run build
- Create component file in
src/dry2/
- Add comprehensive tests in
test/components/
- Create showcase page in
examples/
- Update documentation
- Submit pull request
MIT License - see the LICENSE file for details.
- Alpine.js for reactive functionality
- Tailwind CSS for utility-first styling
- Web Components for the foundation
- Mocha and Chai for testing
- π Documentation
- π¬ GitHub Discussions
- π Issue Tracker
- π§ Email Support
β Star us on GitHub β it helps the project grow!
Made with β€οΈ by the DRY2 team