# Custom attributes

A custom attribute allows you to create special properties to enhance and decorate existing HTML elements and components. Natively attributes exist in the form of things such as `disabled` on form inputs or aria text labels. Where custom attributes can be especially useful is wrapping existing HTML plugins that generate their own markup.

## Creating custom attributes

On a simplistic level, custom attributes resemble [components](https://github.com/aurelia/aurelia/blob/master/docs/user-docs/templates/broken-reference/README.md) quite a lot. They can have [bindable properties](/~/revisions/NShYVVc01DvYc5bgBiwq/components/bindable-properties.md), and they use classes for their definitions.

A basic custom attribute looks something like this:

```typescript
export class CustomPropertyCustomAttribute {
}
```

If you were to replace `CustomAttribute` with `CustomElement`, it would be a component. On a core level, custom attributes are a more primitive component form.

Let's create a custom attribute that adds a red background and height to any dom element it is used on:

```typescript
  import { INode } from 'aurelia';
  
  export class RedSquareCustomAttribute {
    constructor(@INode private element: HTMLElement){
        this.element.style.width = this.element.style.height = '100px';
        this.element.style.backgroundColor = 'red';
    }
  }
```

Now, let's use our custom attribute:

```html
<import from="./red-square"></import>

<div red-square></div>
```

We import our custom attribute so the DI knows about it and then use it on an empty DIV. We'll have a red background element with a height of one hundred pixels.

### Explicit custom attributes

The `customAttribute` decorator allows you to create custom attributes, including the name explicitly. Other configuration options include the ability to create aliases.

#### Explicit attribute naming

You can explicitly name the custom attribute using the `name` configuration property.

```typescript
  import { customAttribute, INode } from 'aurelia';
  
  @customAttribute({ name: 'red-square' }) 
  export class RedSquare {
    constructor(@INode private element: HTMLElement){
        this.element.style.width = this.element.style.height = '100px';
        this.element.style.backgroundColor = 'red';
    }
  }
```

#### Attribute aliases

The `customAttribute` allows you to create one or more aliases that this attribute can go by.

```typescript
  import { customAttribute, INode } from 'aurelia';
  
  @customAttribute({ name: 'red-square', aliases: ['redify', 'redbox'] }) 
  export class RedSquare {
    constructor(@INode private element: HTMLElement){
        this.element.style.width = this.element.style.height = '100px';
        this.element.style.backgroundColor = 'red';
    }
  }
```

We can now use our custom attribute using the registered name `red-square` as well as `redify` and `redbox` the following example highlights using both aliases on an element.

```html
<div redify></div>

<div redbox></div>
```

### Single value binding

Sometimes, you want a custom attribute with only one bindable property. You don't need to define the bindable property explicitly to do this, as Aurelia supports custom attributes with single-value bindings.

```typescript
  import { INode } from 'aurelia';

  export class RedSquareCustomAttribute {
    private value;
    
    constructor(@INode private element: HTMLElement){
        this.element.style.width = this.element.style.height = '100px';
        this.element.style.backgroundColor = 'red';
    }
    
    bind() {
        this.element.style.backgroundColor = this.value;
    }
  }
```

The `value` property is automatically populated if a value is supplied to a custom attribute, however, requires you to define the value property as a bindable explicitly.

When the value is changed, we can access it like this:

```typescript
  import { bindable, INode } from 'aurelia';
  
  export class RedSquareCustomAttribute {
    @bindable() private value;
    
    constructor(@INode private element: HTMLElement){
        this.element.style.width = this.element.style.height = '100px';
        this.element.style.backgroundColor = 'red';
    }
    
    bound() {
        this.element.style.backgroundColor = this.value;
    }
    
    valueChanged(newValue: string, oldValue: string){
        this.element.style.backgroundColor = newValue;
    }
  }
```

### Accessing the element

When using the custom attribute on a dom element, there are instances where you want to be able to access the element itself. To do this, you can use the `INode` decorator and `HTMLElement` interface to inject and target the element.

```typescript
  import { INode } from 'aurelia';
  
  export class RedSquareCustomAttribute {
    constructor(@INode private element: HTMLElement){

    }
  }
```

The code above was lifted from the first example, allowing us to access the element itself on the class using `this.element` This is how we can set CSS values and perform other modifications, such as initialising third-party libraries like jQuery and other libraries.

### Custom attributes with bindable properties

In many cases, you might only need custom attributes without user-configurable properties. However, in some cases, you want the user to be able to pass in one or more properties to change the behavior of the custom attribute (like a plugin).

Using bindable properties, you can create a configurable custom attribute. Taking our example from above, let's make the background color configurable instead of always red. We will rename the attribute for this.

```typescript
  import { bindable, INode } from 'aurelia';
  
  export class ColorSquareCustomAttribute {
    @bindable() color: string = 'red';
  
    constructor(@INode private element: HTMLElement){
        this.element.style.width = this.element.style.height = '100px';
        this.element.style.backgroundColor = this.color;
    }
    
    bound() {
      this.element.style.backgroundColor = this.color;
    }
  }
```

We can now provide a color on a per-use basis. Let's go one step further and allow the size to be set too.

```typescript
  import { bindable, INode } from 'aurelia';
  
  export class ColorSquareCustomAttribute {
    @bindable() color: string = 'red';
    @bindable() size: string = '100px';
  
    constructor(@INode private element: HTMLElement){
        this.element.style.width = this.element.style.height = this.size;
        this.element.style.backgroundColor = this.color;
    }
    
    bound() {
      this.element.style.width = this.element.style.height = this.size;
      this.element.style.backgroundColor = this.color;
    }
}
```

### Responding to bindable property change events

We have code that will work on the first initialization of our custom property, but if the property is changed after rendering, nothing else will happen. We need to use the change detection functionality to update the element when any bindable properties change.

```typescript
  import { bindable, INode } from 'aurelia';
  
  export class ColorSquareCustomAttribute {
    @bindable() color: string = 'red';
    @bindable() size: string = '100px';
  
    constructor(@INode private element: HTMLElement){
        this.element.style.width = this.element.style.height = this.size;
        this.element.style.backgroundColor = this.color;
    }
    
    bound() {
      this.element.style.width = this.element.style.height = this.size;
      this.element.style.backgroundColor = this.color;
    }
    
    colorChanged(newColor, oldColor) {
      this.element.style.backgroundColor = newColor;
    }
    
    sizeChanged(newSize: string, oldSize: string) {
      this.element.style.width = this.element.style.height = newSize;
    }
}  
```

As a default convention, bindable property change callbacks will use the bindable property name followed by a suffix of `Changed` at the end. The change callback gets two parameters, the new value and the existing value.

{% hint style="info" %}
Want to learn more about bindable properties and how to configure them? Please reference the [bindable properties section](/~/revisions/NShYVVc01DvYc5bgBiwq/components/bindable-properties.md).
{% endhint %}

Whenever our size or color bindable properties change, our element will be updated accordingly instead of only at render.

### Options binding

Options binding provides a custom attribute with the ability to have multiple bindable properties. Each bindable property must be specified using the `bindable` decorator. The attribute view model may implement an optional `${propertyName}Changed(newValue, oldValue)` callback function for each bindable property.

When binding to these options, separate each option with a semicolon and supply a binding command or literal value, as in the example below. It is important to note that **bindable properties are converted to dash-case when used in the DOM**, while the view model property they are bound to is kept with their original casing.

```typescript
  import { bindable, INode } from 'aurelia';
  
  export class ColorSquareCustomAttribute {
    @bindable() color: string = 'red';
    @bindable() size: string = '100px';
  
    constructor(@INode private element: HTMLElement){
        this.element.style.width = this.element.style.height = this.size;
        this.element.style.backgroundColor = this.color;
    }
    
    bound() {
      this.element.style.width = this.element.style.height = this.size;
      this.element.style.backgroundColor = this.color;
    }
    
    colorChanged(newColor, oldColor) {
      this.element.style.backgroundColor = newColor;
    }
    
    sizeChanged(newSize: string, oldSize: string) {
      this.element.style.width = this.element.style.height = newSize;
    }
}  
```

To use options binding, here is how you might configure those properties:

```html
<import from="./color-square"></import>

<div color-square="color.bind: myColor; size.bind: mySize;"></div>
```

### Specifying a primary property

When you have more than one bindable property, you might want to specify which property is the primary one (if any). If you mostly expect the user only to configure one property most of the time, you can specify it is the primary property through the bindable configuration.

```typescript
  import { bindable, INode } from 'aurelia';
   
  export class ColorSquareCustomAttribute {
    @bindable( {primary: true} ) color: string = 'red';
    @bindable() size: string = '100px';
  
    constructor(@INode private element: HTMLElement){
        this.element.style.width = this.element.style.height = this.size;
        this.element.style.backgroundColor = this.color;
    }
    
    bound() {
      this.element.style.width = this.element.style.height = this.size;
      this.element.style.backgroundColor = this.color;
    }
    
    colorChanged(newColor, oldColor) {
      this.element.style.backgroundColor = newColor;
    }
    
    sizeChanged(newSize, oldSize) {
      this.element.style.width = this.element.style.height = newSize;
    }
}  
```

The above example specifies that color is the primary bindable property. Our code actually doesn't change at all. The way we consume the custom attribute changes slightly.

```html
<import from="./color-square"></import>

<div color-square="blue"></div>
```

Or, you can bind the value itself to the attribute:

```html
<import from="./color-square"></import>

<div color-square.bind="myColour"></div>
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.aurelia.io/~/revisions/NShYVVc01DvYc5bgBiwq/templates/custom-attributes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
