Version: 1.1.0
Maintained by: @dill-lk and the Yaka UI Labs team
The most comprehensive JavaScript library API documentation you'll ever read. Every method, every parameter, every example. 🚀
- Core API
- DOM Manipulation
- Events
- AJAX & HTTP
- Animations
- UI Components
- Forms & Validation
- State Management
- Routing
- Reactivity (Signals)
- Security
- Storage
- Performance
- Premium Features
- Utilities
Main constructor for creating YakaJS objects.
Parameters:
selector(String|Element|Array|Function) - CSS selector, DOM element, array of elements, or DOM ready functioncontext(Element, optional) - Context element to search within
Returns: Yaka object
Examples:
// CSS Selector
_('#myButton');
_('.items');
_('div[data-active="true"]');
// Multiple selectors
_('.btn, .link');
// With context
_('.item', document.getElementById('container'));
// DOM Element
_(document.getElementById('myDiv'));
// Array of elements
_([element1, element2]);
// HTML string
_('<div class="new">Content</div>');
// DOM Ready
_(() => {
console.log('DOM is ready!');
});Iterate over matched elements.
Parameters:
callback(Function) - Function to execute for each elementindex(Number) - Index of current elementelement(Element) - Current DOM elementthis- Bound to current element
Returns: Yaka object (chainable)
Example:
_('.items').each((index, elem) => {
console.log(`Item ${index}:`, elem.textContent);
// 'this' is bound to elem
console.log(this.className);
});Get raw DOM element(s).
Parameters:
index(Number, optional) - Index of element to get
Returns:
- Array of elements (if no index)
- Single element (if index provided)
Example:
const allElements = _('.items').get();
const firstElement = _('.items').get(0);
const lastElement = _('.items').get(-1);Get first element as new Yaka object.
Returns: Yaka object
Example:
_('.items').first().addClass('highlight');Get last element as new Yaka object.
Returns: Yaka object
Example:
_('.items').last().addClass('last-item');Get element at specific index as new Yaka object.
Parameters:
index(Number) - Zero-based index (negative indexes count from end)
Returns: Yaka object
Example:
_('.items').eq(2).css('color', 'red');
_('.items').eq(-1).hide(); // Last itemNumber of matched elements.
Type: Number (property)
Example:
const count = _('.items').length;
console.log(`Found ${count} items`);Get or set text content.
Parameters:
value(String, optional) - Text to set
Returns:
- String (getter)
- Yaka object (setter, chainable)
Example:
// Get text
const text = _('#title').text();
// Set text (safely escapes HTML)
_('#title').text('Hello <script>alert("XSS")</script>');
// Renders as: Hello <script>alert("XSS")</script>
// Chain
_('#title').text('New Title').addClass('active');Get or set HTML content.
Parameters:
content(String, optional) - HTML to setsanitize(Boolean, optional, default: false) - Whether to sanitize HTML
Returns:
- String (getter)
- Yaka object (setter, chainable)
Example:
// Get HTML
const html = _('#container').html();
// Set HTML (unsafe - XSS possible)
_('#container').html('<div>Content</div>');
// Set HTML with sanitization (safe)
const userInput = '<script>alert("XSS")</script><p>Safe content</p>';
_('#container').html(userInput, true);
// Renders: <script>alert("XSS")</script><p>Safe content</p>
// Chain
_('#container').html('<h1>Title</h1>').fadeIn();Security Note: Always use sanitize: true with user-generated content!
Get or set form element value.
Parameters:
value(String|Number, optional) - Value to set
Returns:
- String (getter)
- Yaka object (setter, chainable)
Example:
// Get value
const email = _('#email').val();
// Set value
_('#email').val('user@example.com');
// Clear input
_('#search').val('');
// Chain
_('#input').val('').focus().addClass('active');Get or set attributes.
Parameters:
name(String|Object) - Attribute name or object of name-value pairsvalue(String, optional) - Attribute value
Returns:
- String (getter)
- Yaka object (setter, chainable)
Example:
// Get attribute
const href = _('a').attr('href');
const dataId = _('.item').attr('data-id');
// Set single attribute
_('#link').attr('href', 'https://example.com');
// Set multiple attributes (optimized - computes keys once)
_('#img').attr({
src: 'image.jpg',
alt: 'Description',
width: '300',
'data-lazy': 'true'
});
// Remove attribute
_('#element').attr('disabled', null);Remove attribute.
Parameters:
name(String) - Attribute name
Returns: Yaka object (chainable)
Example:
_('#button').removeAttr('disabled');
_('.links').removeAttr('target');Add CSS class(es).
Parameters:
className(String) - Class name(s) (space-separated)duration(Number, optional) - Animation duration in ms
Returns: Yaka object (chainable)
Performance: Uses batched DOM operations to prevent layout thrashing!
Example:
// Add single class
_('.item').addClass('active');
// Add multiple classes
_('.item').addClass('active highlight selected');
// Add with animation (batched for performance!)
_('.items').addClass('fade-in', 500);
// Chain
_('.btn').addClass('primary').text('Submit');Advanced: When adding classes to multiple elements with animation, YakaJS batches all reads → writes → single reflow for optimal performance. This prevents the "layout thrashing" problem that occurs with traditional implementations.
Remove CSS class(es).
Parameters:
className(String) - Class name(s) (space-separated)duration(Number, optional) - Animation duration in ms
Returns: Yaka object (chainable)
Performance: Uses batched DOM operations!
Example:
// Remove single class
_('.item').removeClass('active');
// Remove multiple classes
_('.item').removeClass('active highlight selected');
// Remove with animation
_('.items').removeClass('fade-in', 500);
// Chain
_('.btn').removeClass('disabled').attr('disabled', null);Toggle CSS class(es).
Parameters:
className(String) - Class name(s) (space-separated)duration(Number, optional) - Animation duration in ms
Returns: Yaka object (chainable)
Example:
// Toggle class
_('.menu').toggleClass('open');
// Toggle multiple
_('.item').toggleClass('active selected');
// Toggle with animation
_('.panel').toggleClass('expanded', 300);Check if element has class.
Parameters:
className(String) - Class name
Returns: Boolean
Example:
if (_('#menu').hasClass('open')) {
console.log('Menu is open');
}
// Use in conditionals
_('.items').each((i, elem) => {
if (_(elem).hasClass('active')) {
// Do something
}
});Get or set CSS styles.
Parameters:
property(String|Object) - CSS property or object of property-value pairsvalue(String|Number, optional) - CSS value
Returns:
- String (getter)
- Yaka object (setter, chainable)
Example:
// Get style
const color = _('#element').css('color');
const width = _('#element').css('width');
// Set single style
_('#element').css('color', 'red');
_('#element').css('fontSize', '16px');
_('#element').css('width', 300); // Adds 'px' automatically
// Set multiple styles
_('#element').css({
color: 'blue',
fontSize: '18px',
padding: '10px 20px',
backgroundColor: '#f0f0f0'
});
// Chain
_('#box').css('display', 'block').fadeIn();Display elements.
Returns: Yaka object (chainable)
Example:
_('.hidden-content').show();
// Chain
_('#message').show().text('Visible now!');Hide elements.
Returns: Yaka object (chainable)
Example:
_('.content').hide();
// Chain
_('#error').hide().text('').removeClass('active');Toggle visibility.
Returns: Yaka object (chainable)
Example:
_('.dropdown').toggle();
// Toggle on click
_('#toggle-btn').on('click', () => {
_('.panel').toggle();
});Append content inside elements.
Parameters:
content(String|Element|Yaka) - Content to append
Returns: Yaka object (chainable)
Example:
// Append HTML string
_('#list').append('<li>New item</li>');
// Append element
const newDiv = document.createElement('div');
_('#container').append(newDiv);
// Append Yaka object
_('#container').append(_('<div>New</div>'));
// Chain
_('#list').append('<li>Item 1</li>').append('<li>Item 2</li>');Prepend content inside elements.
Parameters:
content(String|Element|Yaka) - Content to prepend
Returns: Yaka object (chainable)
Example:
_('#list').prepend('<li>First item</li>');
_('#container').prepend(newElement);Insert content before elements.
Parameters:
content(String|Element|Yaka) - Content to insert
Returns: Yaka object (chainable)
Example:
_('#target').before('<div>Before target</div>');Insert content after elements.
Parameters:
content(String|Element|Yaka) - Content to insert
Returns: Yaka object (chainable)
Example:
_('#target').after('<div>After target</div>');Remove elements from DOM.
Returns: Yaka object
Example:
_('.old-items').remove();
// Remove conditionally
_('.items').each((i, elem) => {
if (_(elem).attr('data-expired') === 'true') {
_(elem).remove();
}
});Remove all child elements.
Returns: Yaka object (chainable)
Example:
_('#container').empty();
// Clear and rebuild
_('#list').empty().append('<li>New item</li>');Clone elements.
Returns: Yaka object
Example:
const clone = _('.template').clone();
_('#container').append(clone);Attach event handler.
Parameters:
event(String) - Event type (e.g., 'click', 'mouseenter')selector(String, optional) - Selector for event delegationhandler(Function) - Event handler function
Returns: Yaka object (chainable)
Memory Management: Use named functions (not anonymous) if you need to remove handlers later!
Example:
// Simple event
_('#button').on('click', (e) => {
console.log('Clicked!', e.target);
});
// Event delegation
_('#list').on('click', '.item', (e) => {
console.log('Item clicked:', this.textContent);
});
// Multiple events on same handler
_('#input').on('focus blur', handleInputChange);
// Named function for later removal
const handleClick = () => console.log('Clicked');
_('#btn').on('click', handleClick);
_('#btn').off('click', handleClick); // Can remove later
// ⚠️ Anonymous functions can't be removed
_('#btn').on('click', () => {}); // Can't remove this!Event Delegation Benefits:
- Handles dynamically added elements
- Better performance for many elements
- Single event listener instead of many
Remove event handler.
Parameters:
event(String) - Event typeselector(String, optional) - Selector (if was delegated)handler(Function, optional) - Specific handler to remove
Returns: Yaka object (chainable)
Example:
// Remove specific handler
const handler = () => console.log('Click');
_('#btn').on('click', handler);
_('#btn').off('click', handler);
// Remove all click handlers
_('#btn').off('click');
// Remove delegated handler
_('#list').off('click', '.item', itemHandler);Attach event handler that fires once.
Parameters:
event(String) - Event typeselector(String, optional) - Selector for delegationhandler(Function) - Event handler
Returns: Yaka object (chainable)
Example:
// Fire once
_('#popup').one('click', '#close', () => {
console.log('Closed once!');
});
// Welcome message
_('#app').one('load', () => {
showWelcomeMessage();
});Trigger event programmatically.
Parameters:
event(String) - Event typedata(Any, optional) - Data to pass to handlers
Returns: Yaka object (chainable)
Example:
// Trigger click
_('#button').trigger('click');
// Trigger with data
_('#button').on('customEvent', (e, data) => {
console.log('Data:', data);
});
_('#button').trigger('customEvent', { msg: 'Hello' });
// Trigger form submission
_('#form').trigger('submit');Attach mouseenter and mouseleave handlers.
Parameters:
handlerIn(Function) - Handler for mouseenterhandlerOut(Function) - Handler for mouseleave
Returns: Yaka object (chainable)
Example:
_('.item').hover(
function() {
_(this).addClass('hover');
},
function() {
_(this).removeClass('hover');
}
);
// Single handler for both
_('.item').hover(function() {
_(this).toggleClass('hover');
});Perform GET request.
Parameters:
url(String) - Request URLdata(Object, optional) - Query parametersoptions(Object, optional) - Request optionstimeout(Number) - Request timeout in msretries(Number) - Number of retry attemptsretryDelay(Number) - Delay between retries in msheaders(Object) - Custom headersonProgress(Function) - Progress callbackonError(Function) - Error callback
Returns: Promise
Example:
// Simple GET
const data = await _.get('https://api.example.com/users');
// With query params
const users = await _.get('/api/users', {
page: 1,
limit: 10
});
// Requests: /api/users?page=1&limit=10
// With options
const posts = await _.get('/api/posts', null, {
timeout: 5000,
retries: 3,
retryDelay: 1000,
headers: {
'Authorization': 'Bearer token123'
},
onProgress: (loaded, total) => {
console.log(`Progress: ${loaded}/${total}`);
},
onError: (error) => {
console.error('Request failed:', error);
}
});
// Error handling
try {
const data = await _.get('/api/data');
console.log(data);
} catch (error) {
console.error('Failed:', error);
}Perform POST request.
Parameters:
url(String) - Request URLdata(Object, optional) - Request bodyoptions(Object, optional) - Same as.get()
Returns: Promise
Example:
// Simple POST
const response = await _.post('/api/users', {
name: 'John Doe',
email: 'john@example.com'
});
// With CSRF token (automatically included)
_.csrf.setToken('csrf-token-123');
const result = await _.post('/api/data', { value: 42 });
// Automatically adds X-CSRF-Token header
// File upload
const formData = new FormData();
formData.append('file', fileInput.files[0]);
await _.post('/api/upload', formData);
// JSON vs FormData
await _.post('/api/json', { data: 'value' }); // Sends as JSON
await _.post('/api/form', formData); // Sends as multipart/form-dataPerform PUT request.
Parameters: Same as .post()
Returns: Promise
Example:
await _.put('/api/users/123', {
name: 'Jane Doe',
email: 'jane@example.com'
});Perform DELETE request.
Parameters: Same as .get()
Returns: Promise
Example:
await _.delete('/api/users/123');
// With confirmation
if (confirm('Delete this item?')) {
await _.delete(`/api/items/${id}`);
}Low-level AJAX request.
Parameters:
options(Object) - Request configurationurl(String, required) - Request URLmethod(String) - HTTP method (default: 'GET')data(Object) - Request dataheaders(Object) - Custom headerstimeout(Number) - Timeout in msretries(Number) - Retry attemptsresponseType(String) - Response type ('json', 'text', 'blob', etc.)
Returns: Promise
Example:
const response = await _.ajax({
url: '/api/data',
method: 'PATCH',
data: { status: 'active' },
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'value'
},
timeout: 10000,
retries: 2,
responseType: 'json'
});All animations are performant and use CSS transitions + requestAnimationFrame!
Fade in elements.
Parameters:
duration(Number, optional, default: 400) - Duration in mscallback(Function, optional) - Completion callback
Returns: Yaka object (chainable)
Example:
_('#message').fadeIn();
_('#message').fadeIn(1000);
_('#message').fadeIn(500, () => {
console.log('Fade complete!');
});
// Chain
_('#box').hide().fadeIn(600);Fade out elements.
Parameters: Same as .fadeIn()
Example:
_('#message').fadeOut(500);Slide down (reveal).
Parameters: Same as .fadeIn()
Example:
_('.dropdown').slideDown(300);Slide up (hide).
Parameters: Same as .fadeIn()
Example:
_('.dropdown').slideUp(300);Slide left (hide to left).
Parameters: Same as .fadeIn()
Example:
_('.sidebar').slideLeft(400);Slide right (reveal from right).
Parameters: Same as .fadeIn()
Example:
_('.panel').slideRight(400);Animate CSS properties.
Parameters:
properties(Object) - CSS properties to animateduration(Number, optional, default: 400) - Duration in mseasing(String, optional, default: 'ease') - Easing function
Returns: Yaka object (chainable)
Supports: Colors (hex, rgb, rgba with alpha!), numeric values, transformations
Example:
// Animate position and size
_('#box').animate({
left: '100px',
top: '50px',
width: '200px',
height: '200px',
opacity: 0.5
}, 1000);
// Animate colors (including rgba with alpha!)
_('#box').animate({
backgroundColor: 'rgba(255, 0, 0, 0.5)',
color: '#00ff00',
borderColor: 'rgb(0, 0, 255)'
}, 800, 'ease-in-out');
// Transform
_('#box').animate({
transform: 'scale(1.5) rotate(45deg)'
}, 600);
// Multiple properties
_('#element').animate({
width: 300,
height: 200,
opacity: 1,
marginLeft: '50px'
}, 1000, 'cubic-bezier(0.4, 0, 0.2, 1)');Color Animation: YakaJS uses smart color interpolation with requestAnimationFrame for smooth color transitions. Supports hex (#ff0000), rgb (rgb(255,0,0)), and rgba (rgba(255,0,0,0.5)) formats!
Bounce animation.
Returns: Yaka object (chainable)
Example:
_('#button').on('click', function() {
_(this).bounce();
});Shake animation.
Example:
_('#error').shake(); // Draw attention to errorPulse animation.
Example:
_('.notification').pulse();Swing animation.
Example:
_('.bell-icon').swing();3D flip animation.
Example:
_('.card').on('click', function() {
_(this).flip3D();
});Rubber band animation.
Example:
_('.button').rubberBand();Create Vuex/Redux-style store.
Parameters:
config(Object) - Store configurationstate(Object) - Initial statemutations(Object) - Synchronous state mutationsactions(Object) - Asynchronous actionsgetters(Object, optional) - Computed state valuesplugins(Array, optional) - Store plugins
Returns: Store object
Example:
const store = _.createStore({
state: {
count: 0,
user: null,
todos: []
},
mutations: {
increment(state) {
state.count++;
},
decrement(state) {
state.count--;
},
setUser(state, user) {
state.user = user;
},
addTodo(state, todo) {
state.todos.push(todo);
}
},
actions: {
async fetchUser({ commit }) {
const user = await _.get('/api/user');
commit('setUser', user);
},
async incrementAsync({ commit }) {
await new Promise(resolve => setTimeout(resolve, 1000));
commit('increment');
}
},
getters: {
doubleCount: state => state.count * 2,
completedTodos: state => state.todos.filter(t => t.completed)
}
});
// Use the store
store.commit('increment');
console.log(store.state.count); // 1
store.dispatch('incrementAsync');
console.log(store.getters.doubleCount); // 2
// Undo/Redo support
store.undo(); // Reverts last mutation
store.redo(); // Reapplies undone mutationSolidJS-inspired reactive primitives for fine-grained reactivity!
Create reactive signal.
Parameters:
initialValue(Any) - Initial value
Returns: Signal function with .set() and .update() methods
Example:
// Create signal
const count = _.signal(0);
// Read value
console.log(count()); // 0
// Set value
count.set(5);
console.log(count()); // 5
// Update with function
count.update(n => n + 1);
console.log(count()); // 6
// Use in DOM
_.effect(() => {
_('#count').text(count());
});
count.set(10); // Automatically updates DOM!Create computed signal.
Parameters:
fn(Function) - Computation function
Returns: Computed signal (read-only)
Example:
const count = _.signal(5);
const doubled = _.computed(() => count() * 2);
const quadrupled = _.computed(() => doubled() * 2);
console.log(doubled()); // 10
console.log(quadrupled()); // 20
count.set(10);
console.log(doubled()); // 20
console.log(quadrupled()); // 40Create reactive effect.
Parameters:
fn(Function) - Effect function
Returns: Cleanup function
Example:
const name = _.signal('John');
const greeting = _.signal('Hello');
// Auto-runs when dependencies change
_.effect(() => {
console.log(`${greeting()}, ${name()}!`);
});
// Logs: Hello, John!
name.set('Jane');
// Logs: Hello, Jane!
greeting.set('Hi');
// Logs: Hi, Jane!
// With cleanup
const dispose = _.effect(() => {
const interval = setInterval(() => {
console.log(count());
}, 1000);
return () => clearInterval(interval); // Cleanup
});
// Stop effect
dispose();Sanitize HTML to prevent XSS.
Parameters:
html(String) - HTML string to sanitize
Returns: String (sanitized HTML)
Example:
const userInput = '<script>alert("XSS")</script><p>Safe content</p>';
const safe = _.security.sanitizeHtml(userInput);
// Returns: '<script>alert("XSS")</script><p>Safe content</p>'
// Use with .html()
_('#content').html(userInput, true); // Automatically sanitizesEscape HTML entities.
Parameters:
text(String) - Text to escape
Returns: String
Example:
const escaped = _.security.escapeHtml('<div>Hello & "welcome"</div>');
// Returns: '<div>Hello & "welcome"</div>'Set CSRF token.
Parameters:
token(String) - CSRF token
Example:
// Set token (from server)
_.csrf.setToken(document.querySelector('[name=csrf-token]').content);
// All POST/PUT/DELETE requests automatically include token
await _.post('/api/data', { value: 42 });
// Includes X-CSRF-Token: your-token headerGet current CSRF token.
Returns: String
Example:
const token = _.csrf.getToken();Voice command recognition. 🎤 UNIQUE TO YAKAJS!
Parameters:
commands(Object) - Map of voice commands to actions
Returns: Recognition object
Example:
// Enable voice control
_.voice.listen({
'click button': () => _('#myButton').click(),
'show menu': () => _('#menu').show(),
'hide menu': () => _('#menu').hide(),
'scroll down': () => window.scrollBy(0, 100),
'scroll up': () => window.scrollBy(0, -100),
'search for *': (query) => {
_('#search').val(query).trigger('submit');
}
});
// Say "click button" to trigger button click!
// Say "search for javascript" to search!Browser Support: Chrome, Edge (requires HTTPS)
VS Code-style command palette.
Parameters:
commands(Array) - Array of command objectstitle(String) - Command titleaction(Function) - Command actionkeywords(Array, optional) - Search keywords
Example:
_.commandPalette([
{
title: 'Open Settings',
action: () => window.location.href = '/settings',
keywords: ['config', 'preferences']
},
{
title: 'Toggle Dark Mode',
action: () => document.body.classList.toggle('dark')
},
{
title: 'Search',
action: () => _('#search').focus()
}
]);
// Press Ctrl+K (Cmd+K on Mac) to open paletteVirtual scrolling for large lists.
Parameters:
container(String|Element) - Container selector or elementitems(Array) - Array of items to renderoptions(Object) - ConfigurationitemHeight(Number) - Height of each item in pxrenderItem(Function) - Item render functionbuffer(Number, optional) - Buffer size
Example:
const items = Array.from({ length: 10000 }, (_, i) => ({
id: i,
name: `Item ${i}`
}));
_.virtualScroll('#list', items, {
itemHeight: 50,
renderItem: (item) => `
<div class="item" data-id="${item.id}">
${item.name}
</div>
`,
buffer: 5
});
// Renders only visible items + buffer
// Handles 10,000+ items smoothly!Onboarding tour with spotlights.
Parameters:
steps(Array) - Array of tour stepstarget(String) - Selector for target elementtitle(String) - Step titlecontent(String) - Step contentposition(String, optional) - Tooltip position
options(Object, optional) - Tour optionsshowProgress(Boolean) - Show step progresskeyboard(Boolean) - Enable keyboard navigation
Example:
_.tour([
{
target: '#welcome',
title: 'Welcome!',
content: 'This is your dashboard.'
},
{
target: '#menu',
title: 'Navigation',
content: 'Use this menu to navigate.',
position: 'right'
},
{
target: '#settings',
title: 'Settings',
content: 'Customize your experience here.',
position: 'bottom'
}
], {
showProgress: true,
keyboard: true
});See ADVANCED_GUIDE.md for complete documentation on:
- Offline Detection -
_.isOnline(),_.onOffline(),_.onOnline() - Clipboard -
_.copy(),_.paste() - WebSocket -
_.ws(url, options) - Lazy Loading -
_.lazyLoad(selector, options) - Pull to Refresh -
_.pullToRefresh(callback) - PWA Install -
_.pwaInstall() - Shake Detection -
_.onShake(callback) - Image Cropper -
_.imageCropper(image, options) - Rich Editor -
_.richEditor(selector) - Element Inspector -
_.inspectElement() - Eye Tracking -
_.eyeTracker()
Enable safe mode to prevent crashes.
Returns: Yaka object (chainable)
Example:
// Without safe mode
_('#nonexistent').hide(); // Might crash
// With safe mode
_('#nonexistent').safe().hide().fadeIn(); // Never crashes!
// Perfect for dynamic content
const id = getUserId(); // Might be null
_(`#user-${id}`).safe().show(); // Safe!Debounce function calls.
Parameters:
fn(Function) - Function to debouncedelay(Number) - Delay in ms
Returns: Debounced function
Example:
const search = _.debounce((query) => {
_.get('/api/search', { q: query }).then(results => {
displayResults(results);
});
}, 300);
_('#search').on('input', (e) => search(e.target.value));Throttle function calls.
Parameters:
fn(Function) - Function to throttlelimit(Number) - Time limit in ms
Returns: Throttled function
Example:
const handleScroll = _.throttle(() => {
console.log('Scroll position:', window.scrollY);
}, 100);
_(window).on('scroll', handleScroll);For advanced usage, see:
- ADVANCED_GUIDE.md - Advanced patterns and techniques
- BEST_PRACTICES.md - Performance and security best practices
- MIGRATION_GUIDE.md - Migrating from jQuery
- EXAMPLES.md - Real-world code examples
Found a bug? Want to add a feature? See CONTRIBUTING.md!
Maintained with ❤️ by @dill-lk and the Yaka UI Labs team.