Properties & Attributes
Properties/attributes represent an element's visual state. Examples:
- types
status: error | success | warning - states
expanded | selected | disabled - behaviors
closable | draggable
<nve-alert status="success"></nve-alert>
Properties (@property) in Lit enable setting the property on the element via JavaScript or HTML Attributes.
<nve-alert status="success"></nve-alert>
<script type="module">
const alert = document.querySelector('nve-alert');
alert.status = 'warning';
</script>
Learn: by default when you set a property, Lit does not update the corresponding attribute in the DOM for performance. If the attribute serves as a style hook example, :host([disabled]) then you can add the reflect option to the property decorator.
Impossible states
Properties/Attributes should avoid enabling “impossible states”. Conflicting APIs on a single element cause impossible states.
<nve-alert status="success">hello there</nve-alert>
<nve-alert info>hello there</nve-alert>
<nve-alert success>hello there</nve-alert>
<nve-alert warning>hello there</nve-alert>
<nve-alert danger>hello there</nve-alert>
<!-- alert cannot be in a success and error state -->
<nve-alert success danger>hello there</nve-alert>
Boolean Types
Boolean property/attribute type behave the same as native HTML element boolean types. The presence of the attribute is truthy and absence of the attribute is falsy. (MDN Reference)
<nve-alert closable>hello there</nve-alert>
disable-closable, not-closable, closable=”false”)
Primitive Types
While Lit keeps both properties and attributes in sync, do not use complex types like object and array on the API. Since HTML cannot represent JavaScript objects, Lit must JSON parse attributes and reflect them anytime there is a change to ensure the JavaScript property and HTML attribute are in sync. This can be expensive to parse when using an object or array and cause unexpected behaviors such as lost object references for the user.
string | number | boolean
object | array
Complex types cause compatibility and usability issues as it can require the developer to use JavaScript to render content. This can make it difficult for user-generated content like CMS systems or SSR (Server Side Rendering) to easily render static HTML.
@property on built in properties/attributes on the HTMLElement as the decorator overrides the getter/setter and can cause unexpected behavior. read more
Data Elements
Some components exist as a representational view of a pure data structure that cannot be meaningfully distilled into primitive attributes or expressed declaratively as HTML child elements. In these cases a complex type property is acceptable.
A component qualifies as a Data Element when all the following are true:
- The component renders a data structure (arrays, series, matrices) rather than composable UI content.
- The data is not representable using a reasonable number of primitive attributes or slotted children.
- The component is a leaf node -- it does not compose other application-level elements.
<!-- sparkline plots a numeric series — no sensible way to express this as attributes or children -->
<nve-sparkline data="[14, 18, 17, 20, 19, 24, 21]"></nve-sparkline>
Components that meet this criteria should implement the DataElement interface so the pattern is consistent and discoverable across the library.
/** An element that implements a representational view of complex data. */
export interface DataElement<T extends unknown[] | Record<string, unknown>> {
data?: T;
}
The data property should use Lit's @property decorator without the reflect option to avoid serializing large structures back to the DOM attribute.
export class Sparkline extends LitElement implements DataElement<number[]> {
@property({ type: Array }) data?: number[];
}
<!-- data element: the series is a pure data structure with no declarative alternative -->
<nve-sparkline data="[14, 18, 17, 20, 19, 24, 21]"></nve-sparkline>
<!-- alert content is composable UI — use primitives and slots instead -->
<nve-alert data='{"status":"success","message":"hello"}'>
</nve-alert>
Warning: only use DataElement for data structures that have no reasonable declarative HTML representation. If primitive attributes, slots, or child elements can represent the content, prefer those approaches.