diff --git a/incremental-dom/all-tests.ts b/incremental-dom/all-tests.ts
new file mode 100644
index 000000000..099b41e3b
--- /dev/null
+++ b/incremental-dom/all-tests.ts
@@ -0,0 +1,9 @@
+///
+
+declare var describe:any
+,it:any
+,expect:any
+,beforeEach:any
+,afterEach:any;
+
+///
diff --git a/incremental-dom/incremental-dom.d.ts b/incremental-dom/incremental-dom.d.ts
new file mode 100644
index 000000000..a9f3dc27f
--- /dev/null
+++ b/incremental-dom/incremental-dom.d.ts
@@ -0,0 +1,81 @@
+// Type definitions for Incremetal DOM
+// Project: https://github.com/google/incremental-dom
+// Definitions by: Basarat Ali Syed
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+declare module "incremental-dom" {
+ /**
+ * Patches the document starting at el with the provided function. This function
+ * may be called during an existing patch operation.
+ * @param {!Element} el the element to patch
+ * @param {!function} fn A function containing elementOpen/elementClose/etc.
+ * calls that describe the DOM.
+ */
+ export var patch: (el: Node, fn: Function) => void;
+
+ /**
+ * Declares a virtual Element at the current location in the document. This
+ * corresponds to an opening tag and a elementClose tag is required.
+ * @param {string} tag The element's tag.
+ * @param {?string} key The key used to identify this element. This can be an
+ * empty string, but performance may be better if a unique value is used
+ * when iterating over an array of items.
+ * @param {?Array<*>} statics An array of attribute name/value pairs of the
+ * static attributes for the Element. These will only be set once when the
+ * Element is created.
+ * @param {...*} var_args Attribute name/value pairs of the dynamic attributes
+ * for the Element.
+ */
+ export var elementOpen: (tag: string, key?: string, statics?: any[], ...var_args: any[]) => void;
+ /**
+ * Declares a virtual Element at the current location in the document. This
+ * corresponds to an opening tag and a elementClose tag is required. This is
+ * like elementOpen, but the attributes are defined using the attr function
+ * rather than being passed as arguments. Must be folllowed by 0 or more calls
+ * to attr, then a call to elementOpenEnd.
+ * @param {string} tag The element's tag.
+ * @param {?string} key The key used to identify this element. This can be an
+ * empty string, but performance may be better if a unique value is used
+ * when iterating over an array of items.
+ * @param {?Array<*>} statics An array of attribute name/value pairs of the
+ * static attributes for the Element. These will only be set once when the
+ * Element is created.
+ */
+ export var elementOpenStart: (tag: string, key?: any, ...statics: any[]) => void;
+ /***
+ * Defines a virtual attribute at this point of the DOM. This is only valid
+ * when called between elementOpenStart and elementOpenEnd.
+ *
+ * @param {string} name
+ * @param {*} value
+ */
+ export var attr: (name: string, value: any) => void;
+ /**
+ * Closes an open tag started with elementOpenStart.
+ */
+ export var elementOpenEnd: () => void;
+ /**
+ * Closes an open virtual Element.
+ */
+ export var elementClose: () => void;
+ /**
+ * Declares a virtual Element at the current location in the document that has
+ * no children.
+ * @param {string} tag The element's tag.
+ * @param {?string} key The key used to identify this element. This can be an
+ * empty string, but performance may be better if a unique value is used
+ * when iterating over an array of items.
+ * @param {?Array<*>} statics An array of attribute name/value pairs of the
+ * static attributes for the Element. These will only be set once when the
+ * Element is created.
+ * @param {...*} var_args Attribute name/value pairs of the dynamic attributes
+ * for the Element.
+ */
+ export var elementVoid: (tag: string, key?: string, statics?: any, ...var_args: any[]) => void;
+ /**
+ * Declares a virtual Text at this point in the document.
+ *
+ * @param {string} value The text of the Text.
+ */
+ export var text: (value: string) => void;
+}
diff --git a/incremental-dom/tests/functional/attributes-tests.ts b/incremental-dom/tests/functional/attributes-tests.ts
new file mode 100644
index 000000000..80df028c5
--- /dev/null
+++ b/incremental-dom/tests/functional/attributes-tests.ts
@@ -0,0 +1,171 @@
+///
+
+import id = require('incremental-dom');
+var patch = id.patch;
+var elementVoid = id.elementVoid;
+
+describe('attribute updates', () => {
+ var container:any;
+
+ beforeEach(() => {
+ container = document.createElement('div');
+ document.body.appendChild(container);
+ });
+
+ afterEach(() => {
+ document.body.removeChild(container);
+ });
+
+ describe('for conditional attributes', () => {
+ function render(obj:any) {
+ elementVoid('div', '', [],
+ 'data-expanded', obj.key);
+ }
+
+ it('should be present when they have a value', () => {
+ patch(container, () => render({
+ key: 'hello'
+ }));
+ var el = container.childNodes[0];
+
+ expect(el.getAttribute('data-expanded')).to.equal('hello');
+ });
+
+ it('should be present when falsy', () => {
+ patch(container, () => render({
+ key: false
+ }));
+ var el = container.childNodes[0];
+
+ expect(el.getAttribute('data-expanded')).to.equal('false');
+ });
+
+ it('should be not present when undefined', () => {
+ patch(container, () => render({
+ key: undefined
+ }));
+ var el = container.childNodes[0];
+
+ expect(el.getAttribute('data-expanded')).to.equal(null);
+ });
+
+ it('should update the DOM when they change', () => {
+ patch(container, () => render({
+ key: 'foo'
+ }));
+ patch(container, () => render({
+ key: 'bar'
+ }));
+ var el = container.childNodes[0];
+
+ expect(el.getAttribute('data-expanded')).to.equal('bar');
+ });
+ });
+
+ describe('for function attributes', () => {
+ it('should not be set as attributes', () => {
+ var fn = () =>{};
+ patch(container, () => {
+ elementVoid('div', '', null,
+ 'fn', fn);
+ });
+ var el = container.childNodes[0];
+
+ expect(el.hasAttribute('fn')).to.be.false;
+ });
+
+ it('should be set on the node', () => {
+ var fn = () =>{};
+ patch(container, () => {
+ elementVoid('div', '', null,
+ 'fn', fn);
+ });
+ var el = container.childNodes[0];
+
+ expect(el.fn).to.equal(fn);
+ });
+ });
+
+ describe('for object attributes', () => {
+ it('should not be set as attributes', () => {
+ var obj = {};
+ patch(container, () => {
+ elementVoid('div', '', null,
+ 'obj', obj);
+ });
+ var el = container.childNodes[0];
+
+ expect(el.hasAttribute('obj')).to.be.false;
+ });
+
+ it('should be set on the node', () => {
+ var obj = {};
+ patch(container, () => {
+ elementVoid('div', '', null,
+ 'obj', obj);
+ });
+ var el = container.childNodes[0];
+
+ expect(el.obj).to.equal(obj);
+ });
+ });
+
+ describe('for style', () => {
+ function render(style:any) {
+ elementVoid('div', '', [],
+ 'style', style);
+ }
+
+ it('should render with the correct style properties for objects', () => {
+ patch(container, () => render({
+ color: 'white',
+ backgroundColor: 'red'
+ }));
+ var el = container.childNodes[0];
+
+ expect(el.style.color).to.equal('white');
+ expect(el.style.backgroundColor).to.equal('red');
+ });
+
+ it('should update the correct style properties', () => {
+ patch(container, () => render({
+ color: 'white'
+ }));
+ patch(container, () => render({
+ color: 'red'
+ }));
+ var el = container.childNodes[0];
+
+ expect(el.style.color).to.equal('red');
+ });
+
+ it('should remove properties not present in the new object', () => {
+ patch(container, () => render({
+ color: 'white'
+ }));
+ patch(container, () => render({
+ backgroundColor: 'red'
+ }));
+ var el = container.childNodes[0];
+
+ expect(el.style.color).to.equal('');
+ expect(el.style.backgroundColor).to.equal('red');
+ });
+
+ it('should render with the correct style properties for strings', () => {
+ patch(container, () => render('color: white; background-color: red;'));
+ var el = container.childNodes[0];
+
+ expect(el.style.color).to.equal('white');
+ expect(el.style.backgroundColor).to.equal('red');
+ });
+
+ it('should render with the correct style properties for String instances', () => {
+ patch(container, () => render(new String('color: white; background-color: red;')));
+ var el = container.childNodes[0];
+
+ expect(el.style.color).to.equal('white');
+ expect(el.style.backgroundColor).to.equal('red');
+ });
+ });
+});