diff --git a/addon/components/async-svg.js b/addon/components/async-svg.js
new file mode 100644
index 0000000..9aea23c
--- /dev/null
+++ b/addon/components/async-svg.js
@@ -0,0 +1,23 @@
+import Ember from 'ember';
+import Aria from '../mixins/aria';
+import Common from '../mixins/common';
+const PREFIX = '';
+
+const async = Ember.Component.extend(Aria, Common, {
+ _svg: Ember.observer('src', function() {
+ const src = this.get('src').replace(/\.svg$/, '');
+ Ember.$.ajax({
+ method: 'GET',
+ url: `${PREFIX}/${src}.svg`
+ }).done(data => {
+ this.setSVG(data);
+ });
+ return true;
+ })
+});
+
+async.reopenClass({
+ positionalParams: ['src']
+});
+async[Ember.NAME_KEY] = 'async-svg';
+export default async;
diff --git a/addon/components/inline-svg.js b/addon/components/inline-svg.js
new file mode 100644
index 0000000..9fe4e64
--- /dev/null
+++ b/addon/components/inline-svg.js
@@ -0,0 +1,22 @@
+import Ember from 'ember';
+import Aria from '../mixins/aria';
+import Common from '../mixins/common';
+import SVGs from 'svgs';
+
+const inline = Ember.Component.extend(Aria, Common, {
+ _svg: Ember.computed('src', function() {
+ const src = this.get('src') || '';
+ const path = src.replace(/\.svg$/, '').replace(/\//g, '.');
+ const svg = Ember.get(SVGs, path);
+
+ Ember.assert(`No SVG found for ${path}`, svg);
+
+ this.setSVG(svg);
+ })
+});
+
+inline.reopenClass({
+ positionalParams: ['src']
+});
+inline[Ember.NAME_KEY] = 'inline-svg';
+export default inline;
diff --git a/addon/mixins/aria.js b/addon/mixins/aria.js
new file mode 100644
index 0000000..b0df230
--- /dev/null
+++ b/addon/mixins/aria.js
@@ -0,0 +1,10 @@
+import Ember from 'ember';
+
+export default Ember.Mixin.create({
+ labelledBy: Ember.computed('title', 'desc', function() {
+ const title = this.get('title') ? 'title' : '';
+ const desc = this.get('desc') ? ' desc' : '';
+ return `${title}${desc}`;
+ }),
+ role: 'img'
+});
diff --git a/addon/mixins/common.js b/addon/mixins/common.js
new file mode 100644
index 0000000..91bada1
--- /dev/null
+++ b/addon/mixins/common.js
@@ -0,0 +1,60 @@
+import Ember from 'ember';
+import layout from '../templates/components/svg';
+const htmlSafe = Ember.String.htmlSafe;
+
+export default Ember.Mixin.create({
+ layout: layout,
+ tagName: '',
+
+ /**
+ * Initialize SVG on load
+ */
+ init() {
+ this._super(...arguments);
+ Ember.run.schedule('afterRender', () => {
+ this.notifyPropertyChange('src');
+ });
+ },
+ preserveAspectRatio: null,
+ setSVG(data) {
+ const {width, height, x, y} = this.getProperties('width', 'height', 'x', 'y');
+ this.set('svg', htmlSafe(Ember.$(data).find('svg').html()));
+
+ /**
+ * viewBox
+ *
+ * Not required but often included;
+ */
+ const viewBox = Ember.$(data).find('svg').attr('viewBox');
+ if (Ember.typeOf(this.get('viewBox')) === 'undefined' && viewBox) { this.set('viewBox', viewBox); }
+
+ /**
+ * viewport (width, height)
+ *
+ * The visible portion of the SVG. Firefox may object if not defined but isn't
+ * strictly required and you run the risk of cutoff.
+ *
+ * By default if not set on component or in the SVG then a width of 100% will be
+ * used; this is typically the desired behaviour.
+ */
+ const viewWidth = Ember.$(data).find('svg').attr('width');
+ const viewHeight = Ember.$(data).find('svg').attr('height');
+ if (!width) { this.set('width', viewWidth || '100%'); }
+ if (!height && !width && viewHeight) { this.set('height', viewHeight); }
+
+ /**
+ * Aspect Ratio (preserveAspectRatio)
+ *
+ * SVG has a boolean flag to ensure that viewBox and viewport are the same aspect
+ * ratio. If its stated in the file we'll proxy it through but default its not set.
+ */
+ const preserveAspectRatio = Ember.$(data).find('svg').attr('preserveAspectRatio');
+ if (preserveAspectRatio) { this.set('preserveAspectRatio', preserveAspectRatio); }
+
+ const defaultX = Ember.$(data).find('svg').attr('x');
+ const defaultY = Ember.$(data).find('svg').attr('y');
+ if (!x && defaultX) { this.set('x', Ember.$(data).find('svg').attr('x')); }
+ if (!y && defaultY) { this.set('y', Ember.$(data).find('svg').attr('y')); }
+ }
+
+});
diff --git a/addon/templates/components/svg.hbs b/addon/templates/components/svg.hbs
new file mode 100644
index 0000000..5100e5d
--- /dev/null
+++ b/addon/templates/components/svg.hbs
@@ -0,0 +1,20 @@
+
diff --git a/addon/utils/general.js b/addon/utils/general.js
deleted file mode 100644
index e486741..0000000
--- a/addon/utils/general.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// converts slash paths to dot paths so nested hash values can be fetched with Ember.get
-// foo/bar/baz -> foo.bar.baz
-export function dottify(path) {
- return (path || '').replace(/\//g, '.');
-}
-
-// maybe this should be a component with tagName: 'svg' and strip the outer