🌟 A lightweight, pure vanilla JavaScript utility library that makes DOM manipulation and event handling simple and efficient. 🌟
6x smaller than jQuery • Zero dependencies • Modern ES6+ • Performance optimized
<!-- Via jsDelivr CDN --><scriptsrc="https://cdn.jsdelivr.net/gh/lam0819/MicroUI@latest/dist/microui.min.js"></script><!-- Via GitHub Releases --><scriptsrc="https://github.com/lam0819/MicroUI/releases/latest/download/microui.min.js"></script>Why Vanilla JS? • Performance • Examples • Building • Contributing
- Pure Vanilla JS: Zero dependencies, no frameworks, just native JavaScript
- Ultra Lightweight: Only 18.2KB minified (5.1KB gzipped) - 6x smaller than jQuery
- Modern: Built with ES6+ features and Promise-based APIs
- Fast: Event delegation by default, optimized for performance
- Complete: Includes DOM manipulation, AJAX, animations, components, and more
- Simple: Clean, intuitive API that's easy to learn
- No Build Required: Drop in a script tag and start coding
Modern web development has become unnecessarily complex. While frameworks like React, Vue, and Angular are powerful, they often introduce:
- Build Complexity: Webpack, Babel, and countless dependencies
- Bundle Bloat: Megabytes of JavaScript for simple interactions
- Learning Overhead: New syntax, concepts, and paradigms
- Runtime Overhead: Virtual DOM diffing and framework abstractions
jQuery revolutionized web development by making DOM manipulation simple and cross-browser compatible. However:
- Outdated: Built for IE6 era, carries legacy baggage
- Large: 87KB minified, 30KB gzipped - too heavy for modern needs
- Monolithic: Can't tree-shake unused features
- Not Modern: No ES6+, Promises, or modern JavaScript features
"Maximum functionality, minimum complexity"
MicroUI brings back the simplicity of jQuery while embracing modern JavaScript:
// jQuery way (2006)$(document).ready(function(){$('.button').click(function(){$(this).addClass('clicked');});});// MicroUI way (2024)MicroUI.ready(()=>{MicroUI.on('click','.button',function(){MicroUI.addClass(this,'clicked');});});No frameworks. No dependencies. Just JavaScript.
MicroUI is built entirely with native browser APIs, making it:
- No Virtual DOM: Direct DOM manipulation is faster for most use cases
- Zero Runtime Overhead: No framework initialization or abstractions
- Native Speed: Direct access to browser APIs without wrappers
- Memory Efficient: No framework memory footprint
- Familiar API: If you know jQuery, you know MicroUI
- Modern Features: Promises, async/await, ES6+ syntax
- TypeScript Ready: Full type definitions included
- No Build Required: Drop in a script tag and start coding
- Web Standards: Built on stable browser APIs
- Framework Agnostic: Use with React, Vue, or anything
- Future Proof: Vanilla JavaScript never goes out of style
- Zero Breaking Changes: Stable API you can depend on
| Feature | MicroUI | jQuery | React | Alpine.js | Vanilla JS |
|---|---|---|---|---|---|
| Bundle Size | 5.1KB gzipped | 30KB gzipped | 42KB+ gzipped | 15KB gzipped | 0KB |
| Learning Curve | ⭐⭐ Easy | ⭐⭐ Easy | ⭐⭐⭐⭐⭐ Steep | ⭐⭐⭐ Medium | ⭐⭐⭐⭐ Hard |
| Build Required | ❌ Optional | ❌ No | ✅ Yes | ❌ No | ❌ No |
| Modern Syntax | ✅ ES6+ | ❌ ES5 | ✅ JSX | ✅ ES6+ | ✅ Native |
| Component System | ✅ Built-in | ❌ Plugins | ✅ Core | ✅ Directives | ❌ Manual |
| Event Delegation | ✅ Default | ✅ Manual | ❌ Manual | ✅ Auto | ❌ Manual |
| Animation API | ✅ Web Animations | ❌ CSS only | ❌ CSS/Libraries | ❌ CSS only | ✅ Native |
| AJAX Promises | ✅ Native | ❌ Custom | ❌ External | ❌ Fetch | ✅ Native |
| TypeScript | ✅ Included | ⭐ Community | ✅ First-class | ❌ Limited | ✅ Native |
- Content Websites: Blogs, marketing sites, documentation
- E-commerce: Product pages, shopping carts, checkout flows
- Dashboards: Admin panels, analytics interfaces
- Progressive Enhancement: Adding interactivity to existing sites
- Prototyping: Quick experiments and proof of concepts
- Team Onboarding: Easy for junior developers to understand
- Complex SPAs: Applications with heavy state management
- Real-time Apps: Chat applications, collaborative tools
- Data-Heavy UIs: Large tables, complex visualizations
- Team Standardization: If your team is already invested in a framework
// Traditional Framework ComponentfunctionTodoApp(){const[todos,setTodos]=useState([]);const[inputValue,setInputValue]=useState('');constaddTodo=useCallback(()=>{setTodos(prev=>[...prev,{id: Date.now(),text: inputValue}]);setInputValue('');},[inputValue]);return(<div><inputvalue={inputValue}onChange={e=>setInputValue(e.target.value)}onKeyPress={e=>e.key==='Enter'&&addTodo()}/><buttononClick={addTodo}>Add</button>{todos.map(todo=>(<divkey={todo.id}>{todo.text}</div>))}</div>);}// MicroUI ComponentMicroUI.component('todo-app',{template: ` <div> <input class="todo-input" placeholder="Add todo..."> <button class="add-btn">Add</button> <div class="todos"></div> </div> `,events: {'click .add-btn': 'addTodo','keypress .todo-input': function(e){if(e.key==='Enter')this.methods.addTodo();}},methods: {addTodo(){constinput=MicroUI.$('.todo-input');consttext=input.value.trim();if(text){MicroUI.append('.todos',`<div>${text}</div>`);input.value='';}}}});Performance Benefits:
- Faster Initial Load: Smaller bundle = quicker downloads and parsing
- Lower Memory Usage: No framework overhead, minimal runtime footprint
- Better Mobile Performance: Less JavaScript to parse and execute
- Improved Core Web Vitals: Smaller bundles improve Lighthouse scores
MicroUI delivers exceptional performance through modern optimization techniques:
# Production Build Sizes (Automated via GitHub Actions)
Original: ~45KB (source code)
Minified: 18.2KB (60% reduction)
Gzipped: 5.1KB (89% reduction)
# Comparison with Popular Libraries (Gzipped)
jQuery 3.7: 30KB (5.8x larger)
React 18: 13KB (2.5x larger) Vue 3: 16KB (3.1x larger)
Alpine.js: 15KB (2.9x larger)- Event Delegation: All events use delegation by default (faster than direct binding)
- DOM Optimization: Smart caching and batched operations
- Memory Efficient: Minimal memory footprint with automatic cleanup
- Native APIs: Direct browser API usage for maximum speed
- Tree Shakable: Import only the modules you need
MicroUI prioritizes performance through:
- Zero Dependencies: No framework overhead or initialization cost
- Small Bundle Size: 5.1KB gzipped means faster downloads and parsing
- Native JavaScript: Direct browser API access without abstractions
- Event Delegation: Efficient event handling for dynamic content
- Minimal Overhead: Direct DOM manipulation without virtual DOM diffing
# Download time on different connections
MicroUI (5.1KB gzipped):
- Fast 3G: ~50ms
- Slow 3G: ~165ms
- 2G: ~665ms
jQuery (30KB gzipped):
- Fast 3G: ~300ms - Slow 3G: ~1000ms
- 2G: ~4000ms- User Experience: Faster loading = better user engagement
- SEO Benefits: Google factors page speed into search rankings
- Mobile Performance: Critical for slower devices and networks
- Developer Productivity: Less build time, faster development cycles
- Hosting Costs: Smaller bundles = less bandwidth = lower costs
<!-- Via jsDelivr CDN (Latest) --><scriptsrc="https://cdn.jsdelivr.net/gh/lam0819/MicroUI@latest/dist/microui.min.js"></script><!-- Via jsDelivr CDN (Specific Version) --><scriptsrc="https://cdn.jsdelivr.net/gh/lam0819/MicroUI@v1.0.0/dist/microui.min.js"></script><!-- Via unpkg CDN --><scriptsrc="https://unpkg.com/@extralam/microui@latest/dist/microui.min.js"></script>npm install @extralam/microui// ES6 ImportimportMicroUIfrom'@extralam/microui';// CommonJSconstMicroUI=require('@extralam/microui');Download the latest release from GitHub Releases
<!-- Local file --><scriptsrc="microui.min.js"></script><!-- ES Module --><scripttype="module">importMicroUIfrom'https://unpkg.com/@extralam/microui@latest/dist/microui.esm.js';// Your code here</script><!DOCTYPE html><html><head><scriptsrc="https://cdn.jsdelivr.net/gh/lam0819/MicroUI@latest/dist/microui.min.js"></script></head><body><buttonclass="my-button">Click me!</button><script>// DOM readyMicroUI.ready(()=>{// Event handlingMicroUI.on('click','.my-button',function(){this.textContent='Clicked!';// AJAX requestMicroUI.get('/api/data').then(data=>console.log(data));});});</script></body></html>MicroUI is built around a few core principles:
- Event Delegation: All events use delegation for better performance
- Promise-Based: All async operations return Promises
- Modular: Use only what you need
- Vanilla JS: No new syntax or compilation required
MicroUI.ready(()=>{console.log('DOM is ready!');});// Basic eventMicroUI.on('click','.button',function(e){console.log('Clicked:',this);});// Multiple eventsMicroUI.on('mouseenter mouseleave','.hover',function(e){this.classList.toggle('active');});// One-time eventMicroUI.once('click','.one-time',function(){console.log('This only fires once');});// Remove eventsMicroUI.off('click','.button');// Query elementsconstelement=MicroUI.$('.my-element');constelements=MicroUI.$$('.all-elements');// Manipulate classesMicroUI.addClass(element,'active highlight');MicroUI.removeClass(element,'inactive');MicroUI.toggleClass(element,'visible');// Insert contentMicroUI.append('.container','<div>New content</div>');MicroUI.prepend('.container','<div>First content</div>');MicroUI.html('.container','<p>Replace all content</p>');// Attributes and dataMicroUI.attr(element,'id','my-id');MicroUI.data(element,'user',{name: 'John',age: 30});// GET requestMicroUI.get('/api/users').then(users=>console.log(users)).catch(error=>console.error(error));// POST requestMicroUI.post('/api/users',{name: 'John Doe',email: 'john@example.com'}).then(response=>console.log(response));// Load HTMLMicroUI.load('.content','/partial.html');// Fade effectsMicroUI.fadeIn('.element',300);MicroUI.fadeOut('.element',300,()=>console.log('Fade complete'));// Slide effectsMicroUI.slideDown('.dropdown',400);MicroUI.slideUp('.dropdown',400);// Custom animationMicroUI.animate('.box',{transform: ['translateX(0)','translateX(100px)'],opacity: [1,0.5]},{duration: 500,easing: 'ease-out'});Attach an event handler using delegation.
MicroUI.on('click','.button',function(e){console.log('Clicked:',this);});Remove event handlers.
MicroUI.off('click','.button');Attach a handler that fires only once.
MicroUI.once('submit','.form',function(e){e.preventDefault();console.log('Form submitted once');});Trigger a custom event.
MicroUI.trigger('.element','customEvent',{value: 42});Query single element (with caching).
constheader=MicroUI.$('.header');Query multiple elements.
constbuttons=MicroUI.$$('.button');Add one or more classes.
MicroUI.addClass(element,'active highlight');Remove one or more classes.
MicroUI.removeClass(element,'inactive');Toggle a class.
MicroUI.toggleClass(element,'visible');Check if element has class.
if(MicroUI.hasClass(element,'active')){// ...}Perform GET request.
MicroUI.get('/api/data',{headers: {'Authorization': 'Bearer token'}}).then(data=>console.log(data));Perform POST request.
MicroUI.post('/api/users',{name: 'John'}).then(response=>console.log(response));Generic AJAX request.
MicroUI.ajax({url: '/api/data',method: 'PUT',data: {id: 1,name: 'Updated'},headers: {'Content-Type': 'application/json'}}).then(response=>console.log(response));Fade in an element.
MicroUI.fadeIn('.modal',300,()=>{console.log('Fade in complete');});Fade out an element.
MicroUI.fadeOut('.modal',300);Slide down animation.
MicroUI.slideDown('.dropdown',400);Custom animation using Web Animations API.
MicroUI.animate('.box',{transform: ['scale(1)','scale(1.2)','scale(1)'],opacity: [1,0.8,1]},{duration: 1000,iterations: Infinity});Create debounced function.
constsearch=MicroUI.debounce((query)=>{console.log('Searching:',query);},300);Create throttled function.
consthandleScroll=MicroUI.throttle(()=>{console.log('Scrolling');},100);Merge objects.
constconfig=MicroUI.extend({},defaults,userOptions);LocalStorage wrapper.
// SetMicroUI.store.set('user',{name: 'John',age: 30});// Getconstuser=MicroUI.store.get('user');// RemoveMicroUI.store.remove('user');// Clear allMicroUI.store.clear();SessionStorage wrapper.
MicroUI.session.set('token','abc123');consttoken=MicroUI.session.get('token');Create reusable component.
MicroUI.component('counter',{template: ` <div class="counter"> <button class="dec">-</button> <span class="value">{{count}}</span> <button class="inc">+</button> </div> `,state: {count: 0},methods: {increment(){this.state.count++;this.update();},decrement(){this.state.count--;this.update();}},events: {'click .inc': 'increment','click .dec': 'decrement'},lifecycle: {created(){console.log('Component created');},mounted(){console.log('Component mounted');}}});// Mount componentMicroUI.mount('.app','counter',{count: 10});Create event delegation namespace.
constcart=MicroUI.delegate('shoppingCart',{'click .add-to-cart': function(e){console.log('Adding to cart');},'click .remove-item': function(e){console.log('Removing item');}});// Add more handlerscart.on('click','.checkout',handleCheckout);// Remove handlerscart.off('click','.add-to-cart');// Destroy allcart.destroy();microui/
├── dist/
│ ├── microui.js # Development build
│ ├── microui.min.js # Production build
│ └── microui.esm.js # ES Module build
├── src/
│ ├── core/
│ │ ├── dom.js # DOM utilities
│ │ ├── events.js # Event system
│ │ ├── ajax.js # AJAX utilities
│ │ └── utils.js # Helper functions
│ ├── modules/
│ │ ├── animation.js # Animation module
│ │ ├── storage.js # Storage utilities
│ │ ├── component.js # Component system
│ │ └── delegate.js # Delegation system
│ └── index.js # Main entry point
├── examples/
│ ├── basic.html # Basic examples
│ └── advanced.html # Advanced UI components (tabs, modals, dropdowns)
├── tests/
│ ├── dom.test.js
│ ├── events.test.js
│ └── ajax.test.js
├── llms.txt # LLM-friendly codebase documentation
├── package.json
├── rollup.config.js # Build configuration
├── README.md
└── LICENSE
- Node.js 14+
- npm or yarn
# Clone repository
git clone https://github.com/lam0819/microui.git
cd microui
# Install dependencies
npm install
# Development build
npm run build:dev
# Production build
npm run build
# Watch mode
npm run watch
# Run tests
npm test# Run examples server
npm run serveThe project uses Rollup for building:
// rollup.config.jsimport{terser}from'rollup-plugin-terser';importbabelfrom'@rollup/plugin-babel';exportdefault[// Development build{input: 'src/index.js',output: {file: 'dist/microui.js',format: 'umd',name: 'MicroUI'},plugins: [babel({babelHelpers: 'bundled'})]},// Production build{input: 'src/index.js',output: {file: 'dist/microui.min.js',format: 'umd',name: 'MicroUI'},plugins: [babel({babelHelpers: 'bundled'}),terser()]},// ES Module build{input: 'src/index.js',output: {file: 'dist/microui.esm.js',format: 'es'},plugins: [babel({babelHelpers: 'bundled'})]}];# Run all tests
npm test# Run specific test file
npm test dom.test.js
# Run with coverage
npm run test:coverage
# Watch mode
npm run test:watch// tests/dom.test.jsimport{describe,it,expect}from'@jest/globals';importMicroUIfrom'../src/index.js';describe('DOM Utilities',()=>{it('should add classes',()=>{constelement=document.createElement('div');MicroUI.addClass(element,'active highlight');expect(element.classList.contains('active')).toBe(true);expect(element.classList.contains('highlight')).toBe(true);});it('should query elements',()=>{document.body.innerHTML='<div class="test"></div>';constelement=MicroUI.$('.test');expect(element).toBeTruthy();expect(element.className).toBe('test');});});- Interactive Demo Site - Complete showcase with all features
- Basic Examples - Core functionality demonstrations
- Advanced Components - Tabs, modals, dropdowns, accordions, and more
<!DOCTYPE html><html><head><scriptsrc="https://cdn.jsdelivr.net/gh/lam0819/MicroUI@latest/dist/microui.min.js"></script><style>
.todo { padding:10px; margin:5px; background:#f0f0f0; }
.todo.completed { opacity:0.5; text-decoration: line-through; }
</style></head><body><divclass="app"><h1>Todo List</h1><formclass="todo-form"><inputtype="text" class="todo-input" placeholder="Add todo..."><buttontype="submit">Add</button></form><divclass="todos"></div></div><script>MicroUI.ready(()=>{// Handle form submissionMicroUI.on('submit','.todo-form',function(e){e.preventDefault();constinput=MicroUI.$('.todo-input');consttext=input.value.trim();if(text){consttodoId=Date.now();MicroUI.append('.todos',` <div class="todo" data-id="${todoId}"> <input type="checkbox" class="todo-check"> <span class="todo-text">${text}</span> <button class="todo-delete">Delete</button> </div> `);input.value='';// Save to storageconsttodos=MicroUI.store.get('todos')||[];todos.push({id: todoId, text,completed: false});MicroUI.store.set('todos',todos);}});// Handle checkboxMicroUI.on('change','.todo-check',function(){consttodo=MicroUI.closest(this,'.todo');MicroUI.toggleClass(todo,'completed',this.checked);// Update storageconsttodoId=parseInt(todo.dataset.id);consttodos=MicroUI.store.get('todos')||[];constindex=todos.findIndex(t=>t.id===todoId);if(index!==-1){todos[index].completed=this.checked;MicroUI.store.set('todos',todos);}});// Handle deleteMicroUI.on('click','.todo-delete',function(){consttodo=MicroUI.closest(this,'.todo');consttodoId=parseInt(todo.dataset.id);// Fade out and removeMicroUI.fadeOut(todo,300,()=>{MicroUI.remove(todo);// Update storagelettodos=MicroUI.store.get('todos')||[];todos=todos.filter(t=>t.id!==todoId);MicroUI.store.set('todos',todos);});});// Load saved todosconstsavedTodos=MicroUI.store.get('todos')||[];savedTodos.forEach(todo=>{MicroUI.append('.todos',` <div class="todo ${todo.completed ? 'completed' : ''}" data-id="${todo.id}"> <input type="checkbox" class="todo-check" ${todo.completed ? 'checked' : ''}> <span class="todo-text">${todo.text}</span> <button class="todo-delete">Delete</button> </div> `);});});</script></body></html><!DOCTYPE html><html><head><scriptsrc="https://cdn.jsdelivr.net/gh/lam0819/MicroUI@latest/dist/microui.min.js"></script></head><body><divid="app"></div><script>// Define counter componentMicroUI.component('counter',{template: ` <div class="counter" style="padding: 20px; border: 1px solid #ddd; margin: 10px;"> <h3>{{title}}</h3> <button class="dec">-</button> <span style="margin: 0 20px; font-size: 24px;">{{count}}</span> <button class="inc">+</button> <button class="reset">Reset</button> </div> `,props: {title: 'Counter',initial: 0},state: {count: 0},methods: {increment(){this.state.count++;this.update();},decrement(){this.state.count--;this.update();},reset(){this.state.count=this.props.initial;this.update();}},events: {'click .inc': 'increment','click .dec': 'decrement','click .reset': 'reset'},lifecycle: {created(){this.state.count=this.props.initial;}}});// Mount multiple countersMicroUI.mount('#app','counter',{title: 'Products',initial: 0});MicroUI.mount('#app','counter',{title: 'Users',initial: 100});MicroUI.mount('#app','counter',{title: 'Orders',initial: 50});</script></body></html>We welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Add tests for new functionality
- Run tests:
npm test - Commit changes:
git commit -m "Add my feature" - Push to branch:
git push origin feature/my-feature - Submit a pull request
- Use ES6+ features
- Follow ESLint configuration
- Add JSDoc comments for public APIs
- Keep functions small and focused
- Write tests for new features
- Update README.md for user-facing changes
- Update
llms.txtfor codebase architecture changes - Add examples for new features
- Include JSDoc comments for all public APIs
MIT License - see LICENSE file for details.
Created by MicroUI
Inspired by jQuery's simplicity and modern JavaScript best practices.