Problem
The assignableAttributes system supports non-serializable types (objects, arrays, functions) via a _ref manifest pattern — generating ref IDs, storing values in a global KompElement.manifest Map, writing opaque foo_ref="komp-ref-42" attributes to the DOM, and using a FinalizationRegistry for cleanup. This is complex and unconventional.
Since the primary use case is programmatic (new Dropdown({anchor: el})), most non-serializable values don't need DOM representation. Many can be replaced with serializable alternatives, events, or removed from the public API entirely.
Audit
27 non-serializable attributes found across the library:
Callbacks — replace with events
These are function attributes that duplicate what addEventListener already does.
| Component |
Attribute |
Description |
Alternative |
| Floater |
onShow |
Called when floater becomes visible |
Already fires shown event — remove attribute |
| Floater |
onHide |
Called when floater hides |
Already fires hidden event — remove attribute |
| ContentArea |
onchange |
Called on blur after content edited |
Fire a change event with {detail: {value, oldValue}} |
| Dropzone |
onFileDrop |
Called per file dropped |
Already fires filedrop event — remove attribute |
Transform/render functions
These define how something renders or transforms data.
| Component |
Attribute |
Description |
Alternative |
| Input |
dump |
Transforms input value before storing to target |
String key into a named-transforms registry (e.g. "number", "date") |
| Input |
load |
Transforms target value for display |
Same registry approach |
| Select |
dump |
Transforms selected value before storing |
Same as Input |
| Select |
load |
Transforms target value for display |
Same as Input |
| SearchField |
search |
Async function performing the search |
URL string — component fetches and parses JSON |
| SearchField |
result |
Renders a single result item |
HTML template string with ${field} interpolation |
| SearchField |
input |
Factory for the input element |
Object config passed to createElement |
| SearchField |
empty |
Content when no results (when fn) |
Already supports string — drop function variant |
| SearchField |
loader |
Content while loading (when fn) |
Already supports string — drop function variant |
| Resizer |
bounds |
Returns {top,right,bottom,left} constraints |
JSON object or keyword string ("parent", "viewport") |
| TableColumn |
header |
Renders header cell (when fn) |
Already supports string — sufficient |
| TableColumn |
render |
Renders cell content |
Template string with field interpolation |
| SpreadsheetColumn |
input |
Factory for the edit input element |
String type key looked up in a registry |
| SpreadsheetColumn |
copy |
Converts cell value to clipboard format |
Built-in default covers most cases |
| SpreadsheetColumn |
paste |
Converts clipboard data to cell value |
Same as copy |
Internal object references — remove from public API
These are parent-child references passed during construction. They shouldn't be assignableAttributes at all — they're internal wiring.
| Component |
Attribute |
Description |
Alternative |
| Input |
target |
Data object to bind input value to |
Pass internally, remove from public API |
| Select |
target |
Data object to bind selection to |
Same as Input |
| TableRow |
table |
Ref to parent Table |
this.closest('komp-table') or parent injection |
| TableCell |
table |
Ref to parent Table |
Same — DOM traversal or parent injection |
| TableCell |
column |
Ref to TableColumn config |
Column index (number) + lookup from table |
| TableCell |
record |
Data row (when fn) |
Already supports plain object — drop function variant |
Already handled well
- Floater
anchor — has a load() that resolves selector strings
- Floater
container — already accepts strings
Recommendations
- Callbacks (4): Remove — all redundant with existing events
- Internal references (6): Remove from public
assignableAttributes, use DOM traversal or internal injection
- Transform/render functions (15): Consider a registry + template string approach for common cases, keep programmatic escape hatch
- Simplify the ref system: Once the above are addressed, evaluate whether the
manifest/FinalizationRegistry/_ref pattern is still needed
Problem
The
assignableAttributessystem supports non-serializable types (objects, arrays, functions) via a_refmanifest pattern — generating ref IDs, storing values in a globalKompElement.manifestMap, writing opaquefoo_ref="komp-ref-42"attributes to the DOM, and using aFinalizationRegistryfor cleanup. This is complex and unconventional.Since the primary use case is programmatic (
new Dropdown({anchor: el})), most non-serializable values don't need DOM representation. Many can be replaced with serializable alternatives, events, or removed from the public API entirely.Audit
27 non-serializable attributes found across the library:
Callbacks — replace with events
These are function attributes that duplicate what
addEventListeneralready does.onShowshownevent — remove attributeonHidehiddenevent — remove attributeonchangechangeevent with{detail: {value, oldValue}}onFileDropfiledropevent — remove attributeTransform/render functions
These define how something renders or transforms data.
dump"number","date")loaddumploadsearchresult${field}interpolationinputcreateElementemptyloaderbounds{top,right,bottom,left}constraints"parent","viewport")headerrenderinputcopypasteInternal object references — remove from public API
These are parent-child references passed during construction. They shouldn't be
assignableAttributesat all — they're internal wiring.targettargettablethis.closest('komp-table')or parent injectiontablecolumnrecordAlready handled well
anchor— has aload()that resolves selector stringscontainer— already accepts stringsRecommendations
assignableAttributes, use DOM traversal or internal injectionmanifest/FinalizationRegistry/_refpattern is still needed