JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.js"></script>
<div ng-app="app" ng-controller="MainCtrl as mc">
	<rating min="0" max="10" ng-model="mc.data.rating1"></rating>
	<br/>
	<rating nullifier="true" ng-model="mc.data.rating2"></rating>
	<br/>
	<pre><code>{{ mc.data | json }}</code></pre>
</div>

CSS

rating {
	display: inline;
}
.rating-option {
	padding: 0 3px;
	cursor: pointer;
}
.rating-option-active {
	color: #FFD700;
}
.rating-nullifier {
	padding: 0 3px;
	cursor: pointer;
}

JavaScript

var app = angular.module('app', []);

app.controller('MainCtrl', function() {
	this.data = {
		rating1: null,
		rating2: 3
	};
});

app.directive('rating', function() {

	function RatingController() {
		this._ngModel = null;
		this.rating = null;
		this.options = null;
		this.min = typeof this.min === 'number' ? this.min : 1;
		this.max = typeof this.max === 'number' ? this.max : 5;
	}
	
	RatingController.prototype.setNgModel = function(ngModel) {
		this._ngModel = ngModel;
		
		if( ngModel ) {
			ngModel.$render = this._render.bind(this);
		}
	};
	
	RatingController.prototype._render = function() {
		this.rating = this._ngModel.$viewValue != null ? this._ngModel.$viewValue : -Number.MAX_VALUE;
	};
	
	RatingController.prototype._calculateOptions = function() {
		if( this.min == null || this.max == null ) {
			this.options = [];
		}
		else {
			this.options = new Array(this.max - this.min + 1);
			for( var i=0; i < this.options.length; i++ ) {
				this.options[i] = this.min + i;
			}
		}
	};
	
	RatingController.prototype.setValue = function(val) {
		this.rating = val;
		this._ngModel.$setViewValue(val);
	};
	
	Object.defineProperty(RatingController.prototype, 'min', {
		get: function() {
			return this._min;
		},
		set: function(val) {
			this._min = val;
			this._calculateOptions();
		}
	});
	
	Object.defineProperty(RatingController.prototype, 'max', {
		get: function() {
			return this._max;
		},
		set: function(val) {
			this._max = val;
			this._calculateOptions();
		}
	});
	
	return {
		restrict: 'E',
		scope: {
			min: '<?',
			max: '<?',
			nullifier: '<?'
		},
		bindToController: true,
		controllerAs: 'ctrl',
		controller: RatingController,
		require: ['rating', 'ngModel'],
		link: function(scope, elem, attrs, ctrls) {
			ctrls[0].setNgModel(ctrls[1]);
		},
		template:
			'<span ng-repeat="o in ctrl.options" href="#" class="rating-option" ng-class="{\'rating-option-active\': o <= ctrl.rating}" ng-click="ctrl.setValue(o)">{{ o }}</span>' +
			'<span...