{"id":33054342,"url":"https://github.com/dgs700/angular-custom-element","last_synced_at":"2025-11-15T10:01:21.620Z","repository":{"id":21212733,"uuid":"24525644","full_name":"dgs700/angular-custom-element","owner":"dgs700","description":"Web Components Custom Element enhanced directives!","archived":true,"fork":false,"pushed_at":"2015-07-10T02:06:49.000Z","size":645,"stargazers_count":108,"open_issues_count":7,"forks_count":8,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-10-22T13:49:26.821Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dgs700.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-09-27T06:55:38.000Z","updated_at":"2023-11-12T18:26:55.000Z","dependencies_parsed_at":"2022-09-01T18:52:24.894Z","dependency_job_id":null,"html_url":"https://github.com/dgs700/angular-custom-element","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dgs700/angular-custom-element","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgs700%2Fangular-custom-element","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgs700%2Fangular-custom-element/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgs700%2Fangular-custom-element/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgs700%2Fangular-custom-element/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dgs700","download_url":"https://codeload.github.com/dgs700/angular-custom-element/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dgs700%2Fangular-custom-element/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":284538091,"owners_count":27022334,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-11-15T02:00:06.050Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-11-14T04:00:21.582Z","updated_at":"2025-11-15T10:01:21.606Z","avatar_url":"https://github.com/dgs700.png","language":"JavaScript","funding_links":[],"categories":["Interop"],"sub_categories":[],"readme":"# Angular Custom Element \n\n**Upgrade your AngularJS 1.x.x component directives to Web Components (W3C) Custom Elements!**\n\nWhy wait for AngularJS 2.0 to start writing Angular code for the **W3C Web Components** specifications? With just a tiny, 2kb, Custom Element polyfill plus this provider you can define, export, import, and use **Custom Elements** within your AngularJS 1.x.x app or component now.  Your AngularJS element directives can now be real, bonafide Custom Element directives.  The element properties are seemlesly bound to your directive's $scope, so changes from outside Angular will be immediately reflected in your Angular bindings. \n\n\n## Table of Contents\n\n- [Getting and Installing](#getting-and-installing)\n- [Prerequisites](#prerequisites)\n- [API Documentation](#api-documentation)\n    - [Injecting AngularCustomElement into your app](#injecting-angularcustomelement-into-your-app)\n    - [Defining Custom Elements](#defining-custom-elements)\n    - [Options for the Custom Element config object](#options-for-the-custom-element-config-object)\n    - [Enabling Custom Element binding in the directive](#enabling-custom-element-binding-in-the-directive)\n    - [Template bindings](#template-bindings)\n    - [Directive Definition Guidelines](#directive-definition-guidelines)\n- [Contributing](#contributing)\n- [FAQs and Opinions](#faqs-and-opinions)\n    - [What is AngularCustomElement?](#what-is-angularcustomelement)\n    - [Where can it be used?](#where-can-it-be-used)\n    - [When can I use it?](#when-can-i-use-it)\n    - [Why would I want to use it?](#why-would-i-want-to-use-it)\n    - [How does it work?](#how-does-it-work)\n    - [Who is responsible for this?](#who-is-responsible-for-this)\n    - [How is this different from Polymer or X-Tags?](#how-is-this-different-from-polymer-or-x-tags-1)\n    - [What about :unresolved?](#what-about-unresolved)\n    - [Do I have to use the included polyfill?](#do-i-have-to-use-the-included-polyfill)\n- [Release Notes](#release-notes)\n- [License](#license)\n\n\n## Getting and Installing\n\nYou just need to load `angular-custom-element.min.js` after Angular.js and before your app or component modules. The file is available via:\n\n* Bower: `$\u003e bower install angular-custom-element`\n* fork or clone this repo\n* just copy [angular-custom-element.min.js from here](https://raw.githubusercontent.com/dgs700/angular-custom-element/master/dist/angular-custom-element.min.js)\n* NPM: coming soon\n\n## Prerequisites\n\nTo get the most value out of AngularCustomElement its helpful to have good knowledge of the Custom Element specification and the DOM in general. You should also have at least an intermediate level of experience with AngularJS directives and familiarity with the architectures and patterns used in UI component development.  The defacto Custom Elements tutorial can be found here: \n- \u003ca href=\"http://www.html5rocks.com/en/tutorials/webcomponents/customelements/\" target=\"_blank\"\u003eCustom Elements\ndefining new elements in HTML\u003c/a\u003e\n\nComprehensive information on creating UI component directives can be found here:\n- [Web Component Architecture \u0026 Development with AngularJS](https://leanpub.com/web-component-development-with-angularjs/read)\n\n## API Documentation\n\n* Also see the code in the usage examples directory for inline docs.  It's written so the documentation is self-explanitory and you can cut and paste the code into your app to get started.\n\n\n#### Injecting AngularCustomElement into your app\n\n1) Include your element directive and Custom Element provider as dependencies.\n````javascript\nvar app = angular.module('MyApp',['myComponents.elementDirectives', 'customElements']);\n````\n\n#### Defining Custom Elements\n\n2) Inject $customElementsProvider into a config block.\n````javascript\napp.config(['$customElementsProvider', function ($customElementsProvider) {\n````\n\n**The `.register()` method:**\n\n3) Call the .register() function with a tag name (including namespace plus dash plus name)\nand the custom element config object (very similar to X-Tag config). You will also need\nto define matching element directives, i.e. \"tagName1\"...\n````javascript\n$customElementsProvider.register('tag-name1', { elemConfigObj1 })\n    .register('tag-name2', { elemConfigObj2 })\n    .register('tag-name3', { elemConfigObj3 });    \n````\n\n**The `.registerCollection()` method:**\n\nIf you have several custom elements to register, and/or you prefer to maintain the element definition code\nin a location seperate from your App.config() block, then you can use `.registerCollection([definitions])` to \nregister a group of custom elements in the config block.\n\n`.registerCollection()` takes as its argument an array of custom element definition objects each with a \nname string and a definition config object in the same format as would be passed the `.register()` function. They \nshould be keyed as `name:` and `definition:`.\n````javascript\nvar elementDefinitions = [\n    {\n        name: \"el-one\",\n        definition: {...}\n    },\n    {\n        name: \"el-two\",\n        definition: {...}\n    },\n    {\n        name: \"el-three\",\n        definition: {...}\n    }\n];\n\n$customElementsProvider.registerCollection( elementDefinitions );\n````\n\n#### Options for the Custom Element config object\n\nThe format and options are similar to X-Tags, but there are some differences. Also keep in mind\nthat the context of any code placed in the element config object executes *outside of* AngularJS, so \nit should be VanillaJS and framework agnostic.\n\n**parent: element prototype** (optional) is the element prototype we wish to inherit from. \nIt defaults to HTMLElement. You may inherit from standard HTML elements or other custom elements.\n````javascript\nparent: HTMLButtonElement,\n````\nAll Custom Elements created with this module can be retrieved from a global registry map. To create\na Custom Element that inherits from another just reference the parent like this:\n````javascript\nregister('smarter-button', {\n    parent: window.registeredElements['smart-button']\n    ...\n````\n\n**extends: tag name** (optional) will include all of the parent's properties, but\nthe `\u003ctagname is=\"custom-element\"\u003e` tag syntax must appear in the DOM.\nIn this situation a matching element directive will not work.  The yet-to-be-coded\nwork around will likely be a matching tag name directive that wraps the real element,\nOr you can just use the real tag in the template along with the directive replace:true option for now.\nEither way, we want the HTML monkeys to be able to use `\u003ccustom-element\u003e` syntax for \ndeclarativeness and simplicity.\n````javascript\nextends: 'button',\n````\n\nThe **properties** object contains definitions for the element's instance (or constructor)\nproperties. \n````javascript\nproperties: {\n````\n\nThe object key (propertyNameOne) becomes a property name on the element\n````javascript\n    propertyNameOne: {\n````\n\nInclude a **get** function (optional) if any calculations or adjustments to the value are needed\nThe syntax is the same as an ES5 Object property getter.\n````javascript\n        get: function(){\n            // do any value calculations\n            return valueVar;\n        },\n````\nInclude a **set** function (optional) if any value adjustments are needed, or other actions\nthat need to happen upon a change. Unlike the ES5 syntax, this function *must return the property value*.\n````javascript\n        set: function(val){\n            // do any value calculations\n            val = val + 'X';\n            return val;\n        },\n````        \n\nThe `value: intialValue` (optional) option may be used to set the default or initial\nvalue of a property.\n\nNOTE: a) This may be used along with a get and/or set function option which differs from\nactual ES5 property definitions where that is not allowed\n\nNOTE: b) Any initial value provided by a matching attribute will take priority.\n````javascript\n        value: 'I am a new property',\n````\n\nInclude an **attribute object** (optional) with an attribute **name** (optional) to bind the property\nvalue to an attribute value. Using `attribute: {}` will default to the property name lowercased.\nIf the initial markup includes an attribute value, it will be auto assigned to the\nproperty value, so you can initialize custom element props with attribute string values.\n\nInclude **boolean: true** (defaults to false) in order to have the attribute behave as a\nboolean such as \"checked\" or \"selected\". **Note** that the behavior is not the same as the actual *value*.\nTo set a boolean property/attribute's initial value to true, you must also include \n`value: true` as well.\n\nNote: DO NOT serialize large data objects into attribute strings in order to set the \ninitial value, use some kind of pointer to another property or data store instead.\n````javascript        \n        attribute: {\n            name: 'property-one',\n            boolean: true  // default is false\n        }\n    },\n````\n\n**readOnly** set to **true** creates a read only property (defaults to false). You must also \ninclude an initial **value** option and no matching attribute (it is ignored).\n````javascript        \n        readOnly: true\n    }\n},\n````\n\nThe **callbacks** object follows the W3C Custom Elements spec except that the names are \nshortened similar to X-Tags and Polymer configs.  This object and any callback functions are\noptional. The callbacks execute in the context of the element instance so `this` may be used to \nreference the element instance and its properties.\n\n**Best Practice:** To ensure that your components are portable, shareable, and reusable, the component \n(element) should have NO knowledge of anything outside its boundaries. This means you should not have any\ndirect references to any application or global vars in your callbacks.  Any initialization values \nshould be *injected* into the element. Use attributes for primatives and pointers to anything else, or have a\n\"container\" component or application inject any necessary instantiation data or logic. \n````javascript\ncallbacks: {\n````\n\nThe **created** callback is called upon custom element instantiation which is effectively the element\nconstructor function (for the custom parts). This happens when the browser finds a tag on load parse, \nor elemement is created programatically including from a template.  Any special initialization tasks that \nyou would typically have in a \"constructor function\" would go here.\n````javascript    \n    created: function(){\n        // include any special logic\n        // console.log('created')\n    },\n````\n\nThe **attached** callback is called when the element is inserted into the DOM. Any tasks that \nrequire the DOM to be in place would go here.\n````javascript    \n    attached: function(){\n        //console.log('I am now in the DOM')\n    },\n````\n\nThe **detached** callback is called when the element is removed from the DOM. Any cleanup such as\ndestruction of event bindings would go here.\n````javascript    \n    detached: function (){\n        // include any cleanup logic\n        //console.log('detached')\n    },\n````\n\nThe **attributeChanged** callback is called upon any attribute change including any set programatically\nduring element instantiation (but not if the elem already exists in markup).\n````javascript    \n    attributeChanged: function(attrName, oldVal, newVal){\n        //console.log('attributeChanged', attrName, oldVal, newVal)\n    }\n},\n````\n\nThe **members** object contains any Custom Element Prototype Methods and Properties.  These would be\nakin to class members in which every element instance has access to the same function or value.\n````javascript\nmembers: {\n````\n\nTypically any component logic would be placed in functions here. There are no ES5 object options. Just include a name and function.\n````javascript    \n    elementMethodName: function(args){\n        // logic available to any element instance of this type\n        // by calling elem.elementProtoMethod(args)\n        // All of your custom element \n    },\n````\n\nPrototype properties - in the RARE case where a property needs to be accessable by ALL element instances of\nthis type, define it here. Any data binding to directive $scope requires an explicit event\nlistener attached to the document (see below).\nOne example use case might be a re-themeing of all elements during a page app lifecycle.\nThe attribute option is not available for these. All other options are the same as in the\nproperties object.\n````javascript    \n    memberPropName: {\n        // same as element property\n        get: function(val){\n            return val;\n        },\n        // same as element property\n        set: function(val){\n            val = val + 'X';\n            return val;\n        },\n        // same as element property\n        value: \"blah blah\",\n        // same as element property\n        // most prototype properties if needed would ideally be readOnly\n        readOnly: true\n    }\n}\n````\n\n\n#### Enabling Custom Element binding in the directive\n\n**Inject the Custom Element service into the directive**\n````javascript\nangular.module( 'myComponents.tagName1', ['customElements'] )\n    .directive( 'tagName1', [\n        '$customElements', function($customElements){ ...\n````\n\n**Call $watchElement( scope, element, [true (no bindings)] )** in your directive link or controller function:\n\nThis takes care of binding all custom properties\nto the directive's $scope including triggering a $digest() when\nany custom property is changed from outside of Angular. Two or more \nframeworks can share the same custom elements and no boilerplate!\n\nAfter this line you can enjoy the full power of AngularJS' framework tools\nwhen interacting with your Custom Element. You can have normal bindings\nin your templates and controllers: `$scope.el.propertyName` or `{{el.propertyName}}`.\n````javascript\n$customElements.$watchElement( $scope, $element, [noBindings] );\n````\nPerformance edge case: Under the hood, $watchElement binds a callback function to each \nof the custom element's property setters that calls scope.$digest() asynchronously after\na change. This is what enables the Custom Element API to be framework independent and\nshareable between AngularJS and other frameworks, toolkits, etc.\n\nHowever, there is no easy way to tell where the change came from- the element directive or\nsomething outside of Angular's scope including a container element or another framework. This \nmeans that changes coming from *within AngularJS* automatically result in a $digest() call, and then\nanother $digest() occurs when the setter callback is invoked. If this module is used \nin a very large AngularJS app that has more than 1-2 thousand active bindings, and nothing else in the page \noutside AngularJS code could possibly cause custom element prop mutations, \nthen **pass `true` for no bindings** as the 3rd argument.\nThis will prevent unnecessary double $digest() calls if there is a noticable lag in UI responsiveness. If it's\npossible to gleen where a change originated from the `prop:changed` event object (see below) you can \nissue an *asynchronous* `$scope.$digest()` call in the callback function to update the bindings.\n\n**Custom Element instance and prototype property change events:**\n\nYou can bind to a property change event on the element.\nSince all prop changes generate a change event\nother frameworks in the page can import and interact with\nthe same component.\n````javascript\n$element.on( 'prop:changed', function(evt){\n    $log.log(evt.detail);\n    $scope.$emit(evt.detail);\n    // $timeout(function(){$scope.$digest()}, 0);\n});\n````\n\nYou can bind to a Custom Elemement prototype property change event if needed\nfor something that affects all elem intances such as a theme change.\n\nNOTE: that these bindings must be specifically destroyed on\nthe $destroy event for the directive to avoid memory leaks \n````javascript\n$document.on( 'member:changed', function(evt){\n    if(evt.detail.propName == 'a prototype prop we need to watch'){\n        // do stuff\n        $log.log(evt.detail);\n        $scope.$emit(evt.detail);\n    }\n});\n````\n\n**Utility functions** \n\nThe **.info( $element )** function returns the original custom element config\nobject for debugging purposes.\n````javascript\nvar info = $customElements.info($element);\n````\n\n**Attempt to bind to a foreign Custom Element** i.e. something generated by X-Tags or Polymer.\nBinding is currently limited to attribute values unless the element\nbroadcasts property change events like those above. \n\nThe $scope and $element params are required. If you know that the custom element dispatches\nan event and its name (`evtName` below) upon property changes then complete binding can be achieved.\nOtherwise attribute names are the fallback. *This function is even more experimental than the rest\nof this module ;-)\n````javascript\n$customElements.$importElement($scope, $element, [array of attr names], evtName);\n````\nNote that if you control the element configuration source code for X-Tags, or even\nPolymer elements, then complete integration with matching AngularJS directives is possible with \nabout 10 extra lines of code. (examples coming soon).\n\n#### `.unresolved` class for FOUC prevention\n\nIf the custom tag markup includes an **unresolved** class,\n`\u003ccustom-tag class=\"unresolved\"\u003e` it will automatically be removed  when the element is\nupgraded. It can be used to match something like an `.unresolved: display none;` CSS rule.\nSee the FAQ regarding the `:unresolved` pseudo class below.\n\n#### Directive Definition Guidelines\n\nThe plan for AngularJS 2.0 Component Directives (based on the current design docs) is to\nsimplify the directive definition object.  Component Directives will automatically have:\n\n* An isolate (component) scope, `scope: {}`\n* Matching restricted to tag names, `restrict: 'E'`\n* Templates appended to the tag (vs replacing the tag), `replace: false`\n\nAn isolate scope is a must for the proper encapsulation of a component. Otherwise it loses \nportability, reusability, etc.  Appended templates are necessary since deleting\nthe custom element tag defeats the entire purpose of using one. It also improves \ndeclarativeness and allows other frameworks in the page to use the custom element. \n\nMatching only via element name in AngularJS 1.x.x is recommended in most cases. The gray area\nwould be Custom Elements that extend existing tags and therefore must use the tag name of the\nextended element with an `is=\"custom-tagname\"` attribute, i.e. `\u003cinput is=\"smart-input\"\u003e`. \n\nThere's no best practice for how to handle this in Angular.  The syntax proposed by the W3C is much less\ndeclarative for \"extended\" tags.  Hopefully that will change, but for now, one suggested\nsolution would be to create a skeleton custom element that acts as a wrapper and proxy for\nthe extended element to the associated directive, and have the extended element as the template\nfor the wrapper element.\n\nYour directive definition will need a link and/or controller function in which to invoke the service\ncommand that data-binds element properties: `$watchElement(scope, element)`.  For simple, stand-alone\ncomponents you should be able to invoke this anywhere.  But if you have a \"complex\" or \"container\" component \nelement that has bindings and interactions with child components, the safest place to invoke $watchElement \nwould be in an actual `postLink: function(scope elem){...}` function block.  postLink is invoked after\nthe full creation and insertion of all children elements.\n\nTo learn more about building component directives with AngularJS plus component best practices, check out my \nbook: [Web Component Architecture and Development with AngularJS](https://leanpub.com/web-component-development-with-angularjs). It is free to download or read online while it is still being completed.\n\n\n#### Template bindings\n\nBinding to custom element properties and functions couldn't be more simple.  After `$watchElement()` is\ninvoked which attaches **el** for the element instance reference to the $scope object, any custom\nproperty or method can be bound in the template. Note that html5 *standard properties* cannot be data-bound\nin your templates, only the the props you define can.  \n\n````html\n\u003c!-- bind to an element function and a tag property --\u003e\n\u003ca ng-click=\"el.doSomething(this)\"\u003e\n    {{ el.bttnText }}\n\u003c/a\u003e\n````\n\n\n## Contributing\n\nIf you like the ideas behind this module, PLEASE help by forking, using, identifying bugs and\nfunctionality that is either missing or could be improved, testing, contributing code for tests,\nbug fixes, and feature improvements.\n\nPlease use the [issue tracker for this repo](https://github.com/dgs700/angular-custom-element/issues) for bugs and suggestions.\n\n\n## FAQs and Opinions\n\n#### What is AngularCustomElement?\n\n**AngularJS Custom Element** is an **Angular provider** that allows you to define and register W3C spec custom elements in an application config block.  It is also an **Angular service** meant to be injected into your matching element directive that auto binds the element's custom properties, and attributes to directive scope.  You can access these properties via `$scope.el.propertyName`, or just `el.propertyName` in your template bindings.\n\nThere is a lot of code boilerplate involved in Custom Element definitions, and even more when it comes time to integrate the element with AngularJS's data-binding.  One of the goals of this provider is to reduce that down to just a little bit of configuration and convention, and keep everything as simple, minimalist, performant, and compatible as possible- just like the rest of AngularJS.\n\nThis module is focused exclusively on Custom Elements because their APIs are the integration point for AngularJS and any other app framework.  Other Web Components APIs, including Shadow DOM, HTML Imports, and Template tags are beyond this scope because their usage is essentially independent of any framework internals and/or the polyfills aren't suitable for current use in widescale production code for one reason or another. For those wishing to use Shadow DOM and template tags within your AngularJS HTML templates and JavaScript, there is nothing in this module that would prevent you from doing so.\n\nInstead of 2-way data-binding, you can now have **3-way data-binding**.\n\n#### Where can it be used?\n\n**All modern browsers** including IE 9+, and any existing or yet to be coded Angular element directives.\n\n#### Why would I want to use it?\n\nBecause Custom Element APIs, which are essentially HTML element attributes, properties, methods and events, are becoming the common interface through which web components, applications, toolkits and even different frameworks interact.  Reusable UI components will no longer be restricted to the scope of a particular framework, and components will inherit logic and data directly from other components or elements.  By moving component specific data and logic out of the controller and onto the element, code shelf-life will become much longer.\n\nUnlike the other Web Component polyfills such as Shadow DOM, the Custom Element registration polyfill is very small, simple and reasonably performant/stable meaning the risk of use in large scale, production web applications now is very low.  One of the goals of this small add-on is to build upon the polyfill in a manner that can be used to enhance any Angular element directive.  Additional goals and opinions of ths module are:\n\n* provide a **simple element config API**, very similar to X-Tags\n* provide an even **simpler service API** (just one line of code in your directive link or controller fn)\n* work across **all modern browsers** (IE9+)\n* be suitable for production grade, consumer facing code (unlike Polymer)\n* be **performant and small** (9kb including polyfill dependency)\n* **export Custom Elements** that can be shared, consumed, and bound by other data-binding frameworks\n* provide **support for importing** and binding to Custom Elements from other sources \n* do one thing, and do it well \n* help component developers write **longer lasting code**\n* help developers to start getting a feel for the **web development APIs of the near future**\n* attempt to reflect, where possible, the decisions about how component directives will function in the AngularJS 2.0 design docs\n* be a **community** driven project\n\n#### When can I use it?\n\n~~From now until AngularJS 2.0 is in widescale production. AngularJS 2.0 Component Directives will replace this functionality.  It seems this lib was already deprecated before it was released~~\nAs long as AngularJS 1.x.x is around which may be quite a while given that AngularJS 2.x is effectively a different framework with no simple upgrade path from 1.x.x\n\n#### How does it work?\n\nAs long as a browser has DOM mutation observer capability, the Custom Element API can be easily shimmed. The one exception is the new css pseudo **:unresolved**, but FOUC can be easily prevented in other ways. Chrome already supports the API natively, and Mozilla will shortly.\n\nThe other task is triggering a $digest cycle for element properties that are mutated from outside Angular. Neither Object.observe or DOM Mutation Observers work with element properties due to certain, potential performance reasons.  However, because we can define element properties using ES5 Object property setters and getters, we can invoke callback functions that include an injected $scope.$digest() and trigger custom change events whenever the property setter is called during a mutation.  Any data-binding framework, not just Angular, can use these hooks and events to bind to the Custom Element.\n\n#### Who is responsible for this?\n\nMyself and anyone who wants to help with testing across browsers and suggestion and/or code to help improve.  There are so many DOM peculiarities and weird use-case situations that it is impossible for one person to conceive of comprehensive test coverage or anticipate every edge-case bug. \n\n#### How is this different from Polymer or X-Tags?\n\nPolymer and X-Tags are both great projects and have been invaluable for introducing the web development community to the upcoming [Web Components](http://www.w3.org/wiki/WebComponents/) standards.  At the core, the Custom Elements API is exactly the same. But unlike the Polymer Framework, this module only provides Custom Element integration because Custom Elements are the only standard that can be safely polyfilled across current browsers (including IE 9+) in a manner acceptable for production level code in terms of performance and risk. Polymer also uses ~~Shadow DOM~~, `\u003ctemplate\u003e` tags, and HTML Imports, all of which really need to be part of browser native code to function correctly, and all versions of IE through 11 are especially problematic. X-Tags, on the other hand, also focuses soley on creation of Custom Elements and is safe for production code across all browsers. But custom elements by themselves, don't really offer much.  You still need something that provides application framework features and tools such as XHR, data-binding, module loading, etc. X-Tags is standalone. It can be integrated with frameworks, but requires a lot of boilerplate code that web app developers are not familiar with.\n\nAngularCustomElement hides all the boilerplate for Custom Element generation and AngularJS integration. AngularJS has all the web app framework conveniences that X-Tags lacks including data-binding, and the 2kb Custom Element polyfill is safe for *production* use across browsers. There is no reason why any AngularJS UI component directive shouldn't be Custom Element based at this point. Getting comfortable with the Custom Element API will offer much greater shelf life for components created today.  When AngularJS 2.0 arrives this will be the default.\n\n#### What about :unresolved?\n\nThe `:unresolved` pseudo class is part of the Custom Element specification.  When implemented, it matches any custom tag in the page markup that hasn't yet been upgraded to a registered custom element- presumably because the code that registers the element has yet to execute. The purpose is to hide any FOUC (flash of unstyled content) similar to the purpose of the `ngCloak` decorator directive. In cases where your custom tag resides in Angular templates `ngCloak` is sufficient to prevent FOUC. But for custom tags present in the initial markup browsers would add the `:unresolved` pseudo class which you can map to a CSS rule.\n\nCSS pseudo class application is performed by the browsers' native code, not JavaScript. Because of this it is typically not possible to polyfill CSS behavior in either a complete or performant way for browsers that do not support it yet.  The Custom Element polyfill bundled with this module was chosen because it is very small(~2kb), fast and does not include gobs of unneeded code.  It also does not try to shiv `:unresolved` behavior. As a work around you can include an `.unresolved` class on your custom tag markup, `\u003ccustom-tag class=\"unresolved\"\u003e`, and the provider will automatically remove the class if it exists when the attached callback is invoked.\n\n#### Do I have to use the included polyfill?\n\nNo, the build script and distribution directory have minified versions with and without the polyfill.  You can use Polymer's webcomponents.js instead if you want to play with shadow DOM and HTML imports. Just keep in mind that webcomponents.js is not suitable for use in production code compatible with current browsers. Now, as of mid-2015, the non-shadow DOM version called webcomponents-lite.js should work, but hasn't yet been tested.\n\n## License and Copyright\n\n**Copyright (c) 2014, 2015 David Shapiro**\n\n**MIT License**\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdgs700%2Fangular-custom-element","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdgs700%2Fangular-custom-element","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdgs700%2Fangular-custom-element/lists"}