Home

Awesome

ngx-tagify

Proper Angular library that wraps @yaireo/tagify. It allows multiple instances of tagify, implements ControlValueAccessor (for use with ngModel and reactive forms), and includes proper type declarations.

Demo

Install

Install via npm:

npm install ngx-tagify

Import module:

import { TagifyModule } from 'ngx-tagify'; 

@NgModule({
  imports: [
    ...
    TagifyModule,
    ...
  ]
})
export class AppModule {}

Include styling (see below).

Component

You can use the <tagify> component either with ngModel or with reactive forms. Either way, it takes a string or an array of TagData, i.e. an Object that contains a unique property value:

interface TagData {
  value: string;
  [key: string]: any;
}

If a string is passed, it gets parsed for tags by Tagify. The returned string is the stringified tags array or, if mode: 'mix', the mixed text and tags string.

Usage with ngModel

Import FormsModule to your module.

<tagify
  [(ngModel)]="tags"
  inputClass="form-control"
  [settings]="settings"
  [whitelist]="whitelist$"
  [readonly]="readonly"
  [disabled]="disabled"
  (add)="onAdd($event)"
  (remove)="onRemove($event)"
></tagify>
import { Component } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { TagData, TagifySettings } from 'ngx-tagify';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
    
  tags: TagData[] = [{ value: 'foo' }];
  // tags = 'foo'; -> if you want to pass as string
    
  settings: TagifySettings = {
    placeholder: 'Start typing...',
    blacklist: ['fucking', 'shit'],
    callbacks: {
      click: (e) => { console.log(e.detail); }
    }
  };
  
  whitelist$ = new BehaviorSubject<string[]>(['hello', 'world']);
  
  readonly = false;
  
  disabled = false;
  
  onAdd(tagify) {
    console.log('added a tag', tagify);  
  }
  
  onRemove(tags) {
    console.log('removed a tag', tags);
  }
  
}

Note: The component only recognizes reference changes, it won't deep check for changes within the array. this.tags.push({value: 'bar'}); won't do anything. Instead, use this.tags = this.tags.concat([{value: 'bar'}]); (or similar) to update changes.

Usage with Reactive Forms

Import ReactiveFormsModule to your module.

<form [formGroup]="form">
  <tagify formControlName="tags"></tagify>
</form>
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  
  form = new FormGroup({
    tags: new FormControl([{ value: 'Reactive' }])
  });
    
  ngOnInit(): void {
      
    this.form.valueChanges.subscribe(value => {
      console.log('form value changed', value);
    });
      
  }
  
}

Predefined values

Use ngModel or reactive forms with an initial string value that gets parsed by Tagify.

If you want to pass predefined tags as text, but receive a tags array as output, pass the value as text between <tagify></tagify>. Mixed text & tags are also supported.

<tagify>tag 1, tag 2</tagify>
<tagify [settings]="{ mode: 'mix' }">
  [[Eric Cartman]] and [[kyle]] do not know [[homer simpson]] because he's a relic.
</tagify>

Angular has problems with hard-coded single curly braces. Use property binding to add predefined tags with json syntax.

originalText = '[[{"id":200, "value":"cartman", "title":"Eric Cartman"}]] and [[kyle]] do not know [[{"value":"homer simpson", "readonly":true}]] because he\'s a relic.';
<tagify [settings]="{ mode: 'mix' }">
  {{ originalText }}
</tagify>

Inputs

<!-- --><!-- -->
settingsType: TagifySettings<br>See tagify/Settings.
inputClassType: string<br>Apply one or more CSS classes to the input field (e.g. Bootstrap's form-control).
whitelistType: Observable<string[]|TagData[]><br>Execution of the observable updates the whitelist of tagify. You can listen to user's inputs and update the whitelist respectively using this observable.
readonlyType: boolean<br>Dynamically change readonly status.
disabledType: boolean<br>Dynamically change disabled status.
nameType: string<br>Use the name attribute if you want to access the tagify component via the service. This name should be unique.

Outputs

<!-- --><!-- -->
addFires when a tag has been added.
removeFires when a tag has been removed.
tInputListen to the input event of the tagify input element.

Listen to all other events by defining respective callbacks (tagify/Events).

Service

You can also gain access to the full tagify API via a service. Provide a name, such that the tagify instance will be available via the service.

<tagify name="example"></tagify>
<button (click)="addTags()">Add tags</button>
import { Component } from '@angular/core';
import { TagifyService } from 'ngx-tagify';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  
  constructor(
    private tagifyService: TagifyService
  ) {}
  
  addTags() {
    this.tagifyService.get('example').addTags(['this', 'is', 'cool']);
  }
  
}

The original Tagify class is also exposed and can be used for type declarations or custom implementations.

import { Tagify } from 'ngx-tagify';

const tagify: Tagify = new Tagify(inputElement);

Styling

You have two options to include the styling of Tagify.

Option 1: Modify your angular.json by adding the .scss file to the styles property.

"options": {
  "styles": [
    "node_modules/ngx-tagify/styles/tagify.scss",
    "src/styles.scss"
  ]
}

Option 2: If you want to override some of the styling, import it to a sass file. Have a look at tagify/CSS Variables and respective demo page for details.

// src/styles.scss
@import "ngx-tagify/styles/tagify";

.tagify
  --tags-border-color: #ff0000;

Usage with Bootstrap

If you are using Bootstrap as CSS framework (as used in the demo), you might need to tweak some styles in order that Tagify looks pretty:

.tagify
  --tag-pad: 0 0.5rem;  
  line-height: 1.5;

.tagify__input:empty::before
  line-height: inherit;

.tagify.form-control
  height: unset;

FAQ

I'm getting TS compilation error!

You are getting TypeScript compilation error with an error output like this:

 node_modules/@types/yaireo__tagify/index.d.ts:475:1
    475 export = Tagify;
        ~~~~~~~~~~~~~~~~
    This module is declared with using 'export =', and can only be used with a default import when using the 'allowSyntheticDefaultImports' flag.

To resolve this issue, set allowSyntheticDefaultImports within compilerOptions in your tsconfig.json:

{
  "compilerOptions": {
    
    "allowSyntheticDefaultImports": true,
    
  }
}