Appearance
x:attr Directive
The x:attr directive is used to bind HTML element attributes to widget properties.
Basic Usage
Syntax
html
<element x:attr:attributeName="expression">- attributeName: HTML attribute name
- expression: Widget property or calculation
Attribute Types
String Values
typescript
@Widget({
selector: '.string-attr',
template: `
<a x:attr:href="linkUrl">Link</a>
<input x:attr:placeholder="placeholderText">
<div x:attr:title="tooltipText">Hover</div>
`
})
export class StringAttrWidget {
@xproperty()
linkUrl: string = 'https://example.com';
@xproperty()
placeholderText: string = 'Search...';
@xproperty()
tooltipText: string = 'Tooltip text';
}Boolean Values
typescript
@Widget({
selector: '.boolean-attr',
template: `
<input x:attr:disabled="isDisabled" type="text">
<input x:attr:readonly="isReadOnly" type="text">
<input x:attr:required="isRequired" type="email">
`
})
export class BooleanAttrWidget {
@xproperty()
isDisabled: boolean = false; // false -> attribute is removed
@xproperty()
isReadOnly: boolean = true; // true -> attribute is added
@xproperty()
isRequired: boolean = false;
}Number Values
typescript
@Widget({
selector: '.number-attr',
template: `
<input x:attr:min="minValue" x:attr:max="maxValue" type="number">
<div x:attr:data-count="itemCount"></div>
`
})
export class NumberAttrWidget {
@xproperty()
minValue: number = 0;
@xproperty()
maxValue: number = 100;
@xproperty()
itemCount: number = 0;
}Nested Properties
typescript
class User {
@xproperty()
name: string = 'John Doe';
@xproperty()
avatar: string = '/avatars/default.png';
}
@Widget({
selector: '.nested-attr',
template: `
<img x:attr:src="user.avatar" x:attr:alt="user.name">
<span x:attr:title="user.name"></span>
`
})
export class NestedAttrWidget {
@xproperty()
user: User = new User();
}Computed Properties
typescript
@Widget({
selector: '.computed-attr',
template: `
<button x:attr:disabled="!canSubmit">Submit</button>
<div x:attr:class="statusClass">Status</div>
`
})
export class ComputedAttrWidget {
@xproperty()
formValid: boolean = false;
@xproperty()
status: string = 'pending';
@xcomputed({ dependencies: ['formValid'] })
get canSubmit(): boolean {
return this.formValid;
}
@xcomputed({ dependencies: ['status'] })
get statusClass(): string {
return `status-${this.status}`;
}
}Conditional Expressions
html
<!-- Ternary operator -->
<input x:attr:type="showPassword ? 'text' : 'password'">
<!-- Null coalescing -->
<img x:attr:src="imageUrl || defaultImage">
<!-- Comparison -->
<button x:attr:disabled="count <= 0">Action</button>Common Uses
Form Controls
html
<input x:attr:value="formData.name" x:attr:disabled="isSubmitting">
<select x:attr:disabled="isLoading">
<option>Options</option>
</select>Media Elements
html
<img x:attr:src="imageUrl" x:attr:alt="imageAlt">
<video x:attr:src="videoUrl" x:attr:poster="posterUrl" controls></video>Data Attributes
html
<div x:attr:data-id="itemId" x:attr:data-status="status">
Item
</div>ARIA Attributes
html
<button
x:attr:aria-label="label"
x:attr:aria-pressed="isPressed">
Accessible Button
</button>Null/Undefined Behavior
typescript
// null/undefined values remove the attribute
this.imageUrl = null; // src is removed from <img> element
this.imageUrl = undefined; // src is removed from <img> element
// Empty string keeps the attribute
this.imageUrl = ''; // remains as <img src="">Summary
- Reactive binding: Attributes update automatically
- Type support: String, number, boolean values
- Nested properties: Access like
user.avatar - Computed properties: Calculated values
- Null-safe: Safe handling of null/undefined
- Performance: Only changed attributes are updated