Mixins / Inside-out composition
@foldkit/ui
@foldkit/ui components already expose a useful consumer seam when they hand typed attribute
bundles to toView. foldkit-mixins-ui turns those bundles into named slots so the same Style and
Behavior model can apply.
Button, Input, Checkbox, Disclosure, Dialog, Popover, Tooltip, Slider, Tabs, RadioGroup, Calendar and more are adapted.
There are two reasons a component may not be covered:
Menu,Listbox,ComboBoxandDatePickerbuild their full element tree internally and expose notoView/attribute bundle seam. There is nowhere for a mixin to attach without a component API change.Toast,FileDrop,VirtualList,DragAndDrop,Anchor,HoverIntentandAnimationsimply do not have adapters yet.FileDrop, for example, exposes the seam an adapter would need.
That distinction matters: one is an architectural boundary, the other is unfinished coverage.
Accessibility contracts
A11y.pattern describes structural accessibility expectations in the same vocabulary as Slots:
const DialogPattern = A11y.pattern({
trigger: { capability: Capability.Interactive, events: [Event.Click] },
content: { capability: Capability.Container },
})
A11y.validate(DialogPattern, DialogSlots)Validation is pure and DOM-independent. It checks the declared contract for missing or hidden slots, incompatible capabilities, and unpublished events or attributes. It does not inspect the rendered DOM and does not claim WCAG certification.
Style as data
Rule-based Style compiles deterministic rule text to deterministic class names. Equal rules share a class; server and client derive the same output without a render-time collector.
That gives the application explicit CSS data:
Style.pseudo / media / supports / container / nest
↓
deterministic class
+ deterministic CSSStyle.stylesheet(...) combines and deduplicates those rules. Input-dependent rule generation is
intentionally restricted: Style.whenInput may choose static pieces, but it cannot create a new
rule graph for every render.
Introspection and tooling
Because Slots and Mixins are data, the package can describe them without rendering a DOM tree. That is useful for tests, DevTools, generated documentation and agent tooling.
Slots.describe, Slot.describe and the Surface bridge expose serializable metadata, while
resolver failures use stable diagnostic codes and structured details.
See the trace
Use the examples in increasing order of scope:
examples/mixins— the focused trace: Surface → SlotView → Style → Behavior.examples/todo-app— a whole application using recipes, input-driven style, Theme, Behaviors and@foldkit/uiadapters.examples/remote— the same view boundary over server-derived state.
pnpm demo runs all three.
Limits
- Mixins can only attach where a view deliberately publishes a slot. That is the point: the extension surface is explicit rather than universal.
- Behavior does not own state. Reach for Model/Submodel when state is required.
- Rule-based Style produces CSS data; the application is responsible for including the resulting stylesheet.
- A component that exposes no render/attribute seam cannot be adapted externally.
A11y.validatechecks contracts, not rendered DOM or WCAG compliance.
Package map
foldkit-mixins— Slots, resolver, Style, Behavior, Theme and A11y.foldkit-mixins-ui—@foldkit/uiadapters.foldkit-mixins-surface— Surface → SlotView bridge.