View Source SaladUI Component Configuration Reference
This document defines the configuration structure for SaladUI components returned by getComponentConfig()
.
Overview
getComponentConfig() {
return {
stateMachine: { /* State definitions and transitions */ },
events: { /* Event handlers by state */ },
hiddenConfig: { /* Visibility control by state */ },
ariaConfig: { /* ARIA attributes by part and state */ }
};
}
State Machine Configuration
Defines component states, transitions, and lifecycle handlers.
Structure
stateMachine: {
stateName: {
enter: "handlerMethod" | handlerFunction, // Called when entering state
exit: "handlerMethod" | handlerFunction, // Called when leaving state
transitions: {
eventName: "targetState" | transitionFunction
}
}
}
Example
stateMachine: {
closed: {
enter: "onClosedEnter",
exit: "onClosedExit",
transitions: {
open: "open",
toggle: "open"
}
},
open: {
enter: "onOpenEnter",
transitions: {
close: "closed",
toggle: "closed"
}
},
loading: {
enter: () => console.log("Loading started"),
transitions: {
complete: "idle",
error: "error"
}
}
}
State Handler Methods
// Method referenced by string
onOpenEnter(params) {
console.log("Dialog opened with", params);
this.pushEvent("opened");
}
// Inline function
enter: (params) => {
this.setupComponent(params);
}
Transition Functions
transitions: {
// Simple transition
open: "open",
// Conditional transition
toggle: (params) => {
return this.state === "open" ? "closed" : "open";
},
// Complex transition logic
submit: (params) => {
if (params.isValid) {
return "success";
} else {
return "error";
}
}
}
Events Configuration
Defines event handlers for different states, organized by event type and target part.
Structure
events: {
stateName: {
mouseMap: {
partName: {
eventType: "action" | handlerFunction
}
},
keyMap: {
keyName: "action" | handlerFunction
},
keyEventTarget: "partName" // Optional: which part receives key events
},
_all: { // Special state: applies to all states
// Event handlers that work in any state
}
}
Mouse Events
events: {
closed: {
mouseMap: {
trigger: {
click: "open", // Trigger transition
mouseenter: "handleMouseEnter", // Call method
mouseleave: (event) => { // Inline function
this.clearHover();
}
},
"menu-item": {
click: "selectItem",
mouseenter: "highlightItem"
}
}
},
open: {
mouseMap: {
overlay: { click: "close" },
"close-button": { click: "close" },
content: {
click: (event) => event.stopPropagation()
}
}
}
}
Keyboard Events
events: {
open: {
keyEventTarget: "content", // Keys are listened on content part
keyMap: {
Escape: "close",
Enter: "confirm",
ArrowDown: () => this.navigateNext(),
ArrowUp: () => this.navigatePrev(),
" ": "toggle",
Tab: (event) => {
// Custom tab handling
this.handleTabNavigation(event);
}
}
},
_all: {
keyMap: {
"?": () => this.showHelp() // Help works in any state
}
}
}
Key Names
Any valid event.key
value can be used:
keyMap: {
"a": "actionA",
"Enter": "confirm",
"Escape": "cancel",
"ArrowDown": "next",
" ": "toggle", // Space key
"F1": "help",
"Delete": "remove",
"Backspace": "back",
"Meta": "showMenu", // Cmd/Windows key
"Control": "multiSelect"
}
Mouse Events
Any valid DOM mouse event can be used:
mouseMap: {
partName: {
"click": "action",
"dblclick": "doubleClick",
"mousedown": "startDrag",
"mouseup": "endDrag",
"mouseenter": "hover",
"mouseleave": "unhover",
"mouseover": "over",
"mouseout": "out",
"contextmenu": "showContext",
"focus": "focused",
"blur": "blurred",
"focusin": "focusIn",
"focusout": "focusOut"
}
}
Hidden Configuration
Controls part visibility based on component state.
Structure
hiddenConfig: {
stateName: {
partName: boolean // true = hidden, false = visible
}
}
Example
hiddenConfig: {
closed: {
content: true, // Hide content when closed
overlay: true,
"loading-spinner": true
},
open: {
content: false, // Show content when open
overlay: false,
"close-button": false
},
loading: {
content: true,
"loading-spinner": false, // Show spinner when loading
"error-message": true
},
error: {
content: true,
"loading-spinner": true,
"error-message": false // Show error when in error state
}
}
How It Works
When component transitions to a state:
- Gets visibility rules for that state
- For each part in the rules:
- Sets
element.hidden = true
if rule istrue
- Sets
element.hidden = false
if rule isfalse
- Sets
- Parts not mentioned in rules keep their current visibility
ARIA Configuration
Sets accessibility attributes on parts based on state.
Structure
ariaConfig: {
partName: {
all: { attribute: "value" }, // Always applied
stateName: { attribute: "value" } // Applied in specific state
}
}
Basic Example
ariaConfig: {
trigger: {
all: { role: "button", haspopup: "dialog" },
open: { expanded: "true" },
closed: { expanded: "false" }
},
content: {
all: { role: "dialog" },
open: { hidden: "false" },
closed: { hidden: "true" }
}
}
Attribute Mapping
// Config -> HTML
role: "button" // -> role="button"
expanded: "true" // -> aria-expanded="true"
hidden: "true" // -> aria-hidden="true"
labelledby: "title-id" // -> aria-labelledby="title-id"
Dynamic Values
ariaConfig: {
slider: {
all: {
role: "slider",
valuemin: () => this.min.toString(),
valuenow: () => this.value.toString()
}
}
}
Common Patterns
// Dialog
ariaConfig: {
trigger: {
all: { haspopup: "dialog" },
open: { expanded: "true" },
closed: { expanded: "false" }
},
content: {
all: { role: "dialog" }
}
}
// Menu
ariaConfig: {
trigger: {
all: { haspopup: "menu" },
open: { expanded: "true" }
},
content: { all: { role: "menu" } },
item: { all: { role: "menuitem" } }
}
// Tabs
ariaConfig: {
list: { all: { role: "tablist" } },
trigger: {
all: { role: "tab" },
active: { selected: "true" }
},
content: { all: { role: "tabpanel" } }
}
Complete Example
getComponentConfig() {
return {
stateMachine: {
closed: {
enter: "onClosedEnter",
transitions: {
open: "open",
toggle: "open"
}
},
open: {
enter: "onOpenEnter",
transitions: {
close: "closed",
toggle: "closed",
select: "closed"
}
}
},
events: {
closed: {
mouseMap: {
trigger: { click: "open" }
},
keyMap: {
Enter: "open",
" ": "open",
ArrowDown: "open"
}
},
open: {
keyEventTarget: "content",
mouseMap: {
overlay: { click: "close" },
item: { click: "selectItem" }
},
keyMap: {
Escape: "close",
ArrowDown: () => this.navigateNext(),
ArrowUp: () => this.navigatePrev()
}
}
},
hiddenConfig: {
closed: {
content: true,
overlay: true
},
open: {
content: false,
overlay: false
}
},
ariaConfig: {
trigger: {
all: { haspopup: "listbox" },
open: { expanded: "true" },
closed: { expanded: "false" }
},
content: {
all: { role: "listbox" }
},
item: {
all: { role: "option" },
selected: { selected: "true" },
unselected: { selected: "false" }
}
}
};
}