Skip to main content

Props, Attributes & the .props Contract

Dim components receive data from the parent as HTML attributes, the .props property, and light-DOM children. Understanding which channel to use prevents silent bugs and security issues.


Three input channels

ChannelBest forExample
AttributesStrings, numbers, booleans, JSON objectstransitionId="3"
.propsFunctions, live objects, non-JSON data.props=${{ onSave, user }}
ChildrenComposition / slots<my-card>Hello</my-card>

Inside define(), Dim merges attributes and .props into a single props object passed to your functional component.


Case-insensitive prop names

HTML lowercases attribute names. Dim resolves props case-insensitively:

// Parent sets attribute transitionId — stored as transitionid in DOM
html`<page-view transitionId="${id}"></page-view>`

// Inside component, both work via readProp():
props.transitionId === props.transitionid

Prefer .props for camelCase-heavy APIs to avoid ambiguity.


JSON object attributes

The Dim html template helper supports React-like attr={{ ... }} syntax, but values are parsed with JSON.parse only — not evaluated as JavaScript:

// Valid JSON — works
html`<todo-item todo='{"id":1,"text":"Milk","done":false}'></todo-item>`

// Invalid — functions, undefined, trailing commas, unquoted keys
html`<todo-item todo={{ id: 1, onToggle: toggle }}></todo-item>`
// → console warning; use .props instead

Lit also auto-parses attribute values that start with { or [ when set as plain attributes.


Passing functions and callbacks

Functions must use property binding, not attributes:

const handleDelete = (id) => setTodos(todos.filter((t) => t.id !== id));

return html`
<todo-list
.props=${{
todos,
onDelete: handleDelete,
}}
></todo-list>
`;

Attributes are always strings; a function stringified to the attribute "function …" cannot be called.


The .props property

.props sets the Lit reactive property props: Object on the custom element:

html`<my-form .props=${{ values, errors, onSubmit }}></my-form>`

On each render, Dim merges:

  1. Parsed attributes
  2. Keys from this.props (.props wins on conflict via case-insensitive lookup)

Use .props when passing:

  • Event handlers (@click targets in child templates)
  • Class instances or circular structures
  • Values that change every render without attribute serialization

sharedDependencies injection

Components receive hooks twice — import from dim.ts or use the second argument:

const Child = (props, { useState, html, useRef }) => { ... };

define({ tag: "my-child", component: Child });

Demos often prefer the injected object so federated or lazy-loaded modules share the same hook instances.

Additional injected helpers:

  • querySelector — scoped to the component shadow root
  • getRef(refName) — resolve another component’s useRef target
  • renderChildren — slot / HTML child content
  • keyed — Lit directive for stable list keys

Children and slots

Light DOM children are captured in connectedCallback:

const Wrapper = (props, { html, renderChildren }) => {
return html`
<div class="wrapper">
${renderChildren(props.children)}
</div>
`;
};

Strings with custom element tags use <slot>; plain HTML may use unsafeHTML internally.

See 14. Composition patterns (planned) or Storybook nested components demo for advanced slot usage.


transitionId and other framework props

Framework features read props before your component runs:

html`
<screen-host
transitionId="${viewId}"
transitionDuration="400"
transitionAutoDirection="false"
.props=${{ viewId, data }}
></screen-host>
`;

transitionId on attributes triggers auto view transitions even without .props.


Checklist

  1. Primitives → attributes or JSON in templates
  2. Functions / objects with methods.props
  3. camelCase API → prefer .props
  4. Never pass secrets in attributes (visible in DOM inspector)
  5. Encrypted stateuseStore with { encryptionKey }, not props

Conclusion

The .props contract is Dim’s escape hatch for everything HTML attributes cannot represent. JSON-only attribute parsing is a deliberate security and performance choice.