Skip to content

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