---
description: Using built-in custom attributes and building your own.
---

# 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](../components/components.md) quite a lot. They can have [bindable properties](../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, resolve } from 'aurelia';

  export class RedSquareCustomAttribute {
    private element = resolve(INode) as HTMLElement;
    constructor(){
        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, resolve } from 'aurelia';

  @customAttribute({ name: 'red-square' })
  export class RedSquare {
    private element = resolve(INode) as HTMLElement;

    constructor(){
        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, resolve } from 'aurelia';

  @customAttribute({ name: 'red-square', aliases: ['redify', 'redbox'] })
  export class RedSquare {
    private element = resolve(INode) as HTMLElement;

    constructor() {
        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, resolve } from 'aurelia';

  export class RedSquareCustomAttribute {
    private element = resolve(INode) as HTMLElement;
    private value;

    constructor() {
        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, resolve } from 'aurelia';

  export class RedSquareCustomAttribute {
    private element = resolve(INode) as HTMLElement;

    @bindable() private value;

    constructor() {
        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 {
    private element = resolve(INode) as 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.

{% hint style="info" %}
You can also use `resolve(Element)` or `resolve(HTMLElement)` to get the host element, just like `INode`. However, using `INode` makes it safer when used in Nodejs environment since there will not be a global `Element` or `HTMLElement`. If you are not planning to run your application in Nodejs environment, you can also just use `Element` or `HTMLElement`, like this: `resolve(Element)` or `resolve(HTMLElement)`.
{% endhint %}

### 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, resolve } from 'aurelia';

  export class ColorSquareCustomAttribute {
    @bindable() color: string = 'red';

    constructor(private element: HTMLElement = resolve(INode)){
        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, resolve } from 'aurelia';

  export class ColorSquareCustomAttribute {
    @bindable() color: string = 'red';
    @bindable() size: string = '100px';

    constructor(private element: HTMLElement = resolve(INode)){
        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, resolve } from 'aurelia';

  export class ColorSquareCustomAttribute {
    @bindable() color: string = 'red';
    @bindable() size: string = '100px';

    constructor(private element: HTMLElement = resolve(INode)){
        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](../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, resolve } from 'aurelia';

  export class ColorSquareCustomAttribute {
    @bindable() color: string = 'red';
    @bindable() size: string = '100px';

    constructor(private element: HTMLElement = resolve(INode)){
        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';

    private element = resolve(INode) as HTMLElement;

    constructor() {
        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>
```

## Finding a custom attribute from the DOM

Sometimes, custom attributes are developed in a group of 2 or more, e.g attributes for a dropdown + toggle button inside it, and it's necessary to retrieve the "parent" attribute from a child attribute.
One way to do this is to use `CustomAttribute.closest` function for walking the DOM and finding a particular custom attribute, based on either name, or the constructor.
The name `closest` mimics the DOM API `Element.prototype.closest`.

An example of the `CustomAttribute.closest` is as follow:

```html
<div foo="1">
  <div bar="2">
  </div>
</div>
```

```typescript
import { CustomAttribute, resolve, INode } from 'aurelia';

@customAttribute('bar')
export class Bar {
  host = resolve(INode);
  parent = CustomAttribute.closest(this.host, 'foo');
}
```

Or the following also works if you want to search using the constructor:

```typescript
import { CustomAttribute, resolve, INode } from 'aurelia';
import { Foo } from './foo';

@customAttribute('bar')
export class Bar {
  host = resolve(INode);
  parent = CustomAttribute.closest(this.host, Foo); // <--- use constructor instead of string 'foo'
}
```
