Note: This project is currently paused/on hold and being deprecated in favor of the
radix-themes-playgroundrepo. However, it is being preserved for future reference and potential revival.
This project is a fork of Radix UI primitives that converts React-based UI components to vanilla JavaScript. The goal was to remove React dependencies and create a pure vanilla JavaScript library of UI primitives that maintain the same accessibility, functionality, and API patterns as the original React components.
- Status: 🟡 Paused/On Hold
- Components Converted: 21 out of ~50+ total Radix UI components
- Last Updated: December 2024
- Build Status: ✅ All components building successfully
- Component Base Class: Abstract base class providing DOM manipulation, event handling, and lifecycle management
- State Management: Custom StateManager class replacing React's useState and useControllableState
- Event System: Custom EventTarget class replacing React's context system
- Build System: Configured tsup for CJS/ESM builds with TypeScript support
- Accordion - Collapsible content sections
- AlertDialog - Modal confirmation dialog
- AspectRatio - Maintains aspect ratio for responsive content
- Avatar - User avatar with image loading states
- Checkbox - Form input with controlled state
- ContextMenu - Right-click context menu with touch support
- Dialog - Modal dialog with overlay
- DropdownMenu - Contextual menu
- HoverCard - Hover-triggered card with delay support
- Label - Form label with accessibility
- Popover - Floating content overlay
- Progress - Progress bar with indeterminate/complete/loading states
- RadioGroup - Radio button group
- ScrollArea - Custom scrollable area with custom scrollbars
- Select - Dropdown selection
- Separator - Visual divider
- Switch - Toggle switch
- Slider - Range input with drag support
- Tabs - Tabbed interface with keyboard navigation
- Tooltip - Hover tooltip with delay support
# Clone the repository
git clone <repository-url>
cd ui-primitives
# Install dependencies
npm install
# Build the vanilla components
cd packages/vanilla
npm run build<!DOCTYPE html>
<html>
<head>
<script type="module">
import { Accordion } from './packages/vanilla/dist/accordion.mjs';
// Create accordion instance
const accordion = Accordion.create('#my-accordion', {
type: 'single',
defaultValue: 'item-1'
});
// Listen for events
accordion.addEventListener('valueChange', (event) => {
console.log('Accordion value changed:', event.detail.value);
});
</script>
</head>
<body>
<div id="my-accordion" data-accordion>
<div data-accordion-item data-value="item-1">
<button data-accordion-trigger>Item 1</button>
<div data-accordion-content>Content for item 1</div>
</div>
<div data-accordion-item data-value="item-2">
<button data-accordion-trigger>Item 2</button>
<div data-accordion-content>Content for item 2</div>
</div>
</div>
</body>
</html>All components follow a consistent API pattern:
// Create component instance
const component = ComponentName.create(selector, options);
// Listen for events
component.addEventListener('eventName', (event) => {
console.log('Event details:', event.detail);
});
// Update programmatically
component.setValue(newValue);
// Get current state
const value = component.getValue();
// Clean up
component.destroy();packages/vanilla/
├── src/
│ ├── core/ # Base classes and utilities
│ │ ├── Component.ts # Abstract base class
│ │ ├── StateManager.ts # State management system
│ │ ├── EventTarget.ts # Custom event system
│ │ └── index.ts
│ ├── accordion/ # Component implementations
│ ├── checkbox/
│ ├── dialog/
│ └── ... # Other components
├── dist/ # Built files
├── test/ # Unit tests
├── package.json
├── tsup.config.ts # Build configuration
└── tsconfig.json # TypeScript configuration
# Build all components
npm run build
# Watch mode for development
npm run dev
# Run unit tests
npm run test
# Run tests with coverage
npm run test:coverage- CJS: CommonJS format for Node.js compatibility
- ESM: ES modules for modern browsers
- TypeScript: Generated
.d.tsfiles for type safety - Source Maps: Included for debugging
- ✅ Test Framework: Vitest with jsdom environment
- ✅ Test Setup: Mock DOM environment and utilities
- ✅ Component Tests: Accordion, Checkbox, RadioGroup have tests
- ⏳ Coverage: Need tests for remaining 18 components
# Run all tests
npm run test
# Run tests in watch mode
npm run test:watch
# Run tests with UI
npm run test:ui
# Generate coverage report
npm run test:coverageimport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@radix-ui/react-accordion';
function MyAccordion() {
return (
<Accordion type="single" defaultValue="item-1">
<AccordionItem value="item-1">
<AccordionTrigger>Item 1</AccordionTrigger>
<AccordionContent>Content 1</AccordionContent>
</AccordionItem>
</Accordion>
);
}<div data-accordion>
<div data-accordion-item data-value="item-1">
<button data-accordion-trigger>Item 1</button>
<div data-accordion-content>Content 1</div>
</div>
</div>import { Accordion } from '@radix-ui/vanilla';
const accordion = Accordion.create('[data-accordion]', {
type: 'single',
defaultValue: 'item-1'
});- Full ARIA attribute support
- Keyboard navigation
- Screen reader compatibility
- Focus management
- Full TypeScript support
- Generated type definitions
- Compile-time error checking
- No React overhead
- Direct DOM manipulation
- Efficient event handling
- Tree-shakable components
- Familiar API patterns
- Comprehensive documentation
- Consistent component structure
- Easy debugging
- Chrome: 90+
- Firefox: 88+
- Safari: 14+
- Edge: 90+
- Project Overview - Comprehensive project documentation
- Technical Architecture - Detailed technical implementation
- Component Conversion Guide - Step-by-step conversion instructions
This project could be revived in the future for:
- Framework-agnostic UI library: Pure vanilla JavaScript components
- Performance-critical applications: Where React overhead is not desired
- Learning resource: Understanding how React components work under the hood
- Legacy system integration: Adding modern UI components to existing vanilla JS applications
If revived, these components still need conversion:
- High Priority: Toggle, Toggle Group, Collapsible, Navigation Menu
- Medium Priority: Toast, Menubar, Command, Combobox, Calendar, Date Picker
- Low Priority: Carousel, Resizable, Split View, Tree View, Data Table, Form
While this project is currently paused, if you're interested in contributing when it's revived:
- Fork the repository
- Create a feature branch
- Follow the established patterns and conventions
- Add tests for new components
- Update documentation
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Radix UI Team: For the original React primitives that inspired this conversion
- Open Source Community: For the tools and libraries that made this project possible
Note: This project demonstrates that modern, accessible UI components can be built without React while maintaining excellent developer experience and performance. The patterns established here provide a solid foundation for future component development and can be applied to other framework-agnostic UI libraries.