diff --git a/src/components/shared/forms/DateInput.vue b/src/components/shared/forms/DateInput.vue
new file mode 100644
index 0000000..aa2bb48
--- /dev/null
+++ b/src/components/shared/forms/DateInput.vue
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
diff --git a/src/components/shared/forms/croud-date-input.md b/src/components/shared/forms/croud-date-input.md
new file mode 100644
index 0000000..2a29995
--- /dev/null
+++ b/src/components/shared/forms/croud-date-input.md
@@ -0,0 +1,14 @@
+### Basic usage
+Pass through a moment object or an iso string to set the initial value
+
+
+
+### Invalid date
+This component will emit the **invalid-date** event if the date input is cleared down or if moment can't parse the date from the input
+
+
+
+### Validation
+You can use the **min** and **max** props to set the limits of the date input. This is usually handled by the html5 input, but this component will emit a **validation-error** event if the date selected falls outside of the min and max values
+
+
diff --git a/test/unit/forms/DateInput.spec.js b/test/unit/forms/DateInput.spec.js
new file mode 100644
index 0000000..a0e85b1
--- /dev/null
+++ b/test/unit/forms/DateInput.spec.js
@@ -0,0 +1,100 @@
+import Vue from 'vue'
+import moment from 'moment'
+import DateInput from '../../../src/components/shared/forms/DateInput'
+
+const Constructor = Vue.extend(DateInput)
+
+const vm = new Constructor({
+ propsData: {
+ value: moment(),
+ },
+}).$mount()
+
+const input = jest.fn()
+const invalid = jest.fn()
+const validation = jest.fn()
+vm.$on('input', input)
+vm.$on('invalid-date', invalid)
+vm.$on('validation-error', validation)
+
+describe('Date Input', () => {
+ it('should match the snapshot', () => {
+ expect(vm.$el).toMatchSnapshot()
+ })
+
+ describe('events', () => {
+ beforeEach(() => {
+ input.mockReset()
+ invalid.mockReset()
+ validation.mockReset()
+ })
+
+ it('shouldn\'t be in an error state by default', () => {
+ expect(vm.error).toBe(false)
+ })
+
+ it('should fire input event when date changes', (done) => {
+ vm.date = moment().add(1, 'd')
+ vm.$nextTick(() => {
+ expect(input).toBeCalled()
+ done()
+ })
+ })
+
+ describe('invalid date', () => {
+ it('should fire invalid-date event when date is cleared', (done) => {
+ vm.date = ''
+ vm.$nextTick(() => {
+ expect(invalid).toBeCalled()
+ done()
+ })
+ })
+
+ it('should notice an invalid date and add error class', (done) => {
+ vm.date = '2018-04-31'
+ vm.$nextTick(() => {
+ expect(invalid).toBeCalled()
+ expect(vm.error).toBe(true)
+ done()
+ })
+ })
+ })
+
+ describe('validation', () => {
+ it('should fire validation-error event if sooner than min date', (done) => {
+ vm.min = moment().add(1, 'd')
+ vm.max = null
+ vm.date = moment()
+ vm.$nextTick(() => {
+ expect(validation).toBeCalled()
+ expect(vm.error).toBe(true)
+ done()
+ })
+ })
+
+ it('should fire validation-error event if later than max date', (done) => {
+ vm.min = null
+ vm.max = moment().subtract(1, 'd')
+ vm.date = moment()
+
+ vm.$nextTick(() => {
+ expect(validation).toBeCalled()
+ expect(vm.error).toBe(true)
+ done()
+ })
+ })
+
+ it('should not fire validation-error if between min and max', (done) => {
+ vm.min = moment().subtract(1, 'd')
+ vm.max = moment().add(1, 'd')
+ vm.date = moment()
+
+ vm.$nextTick(() => {
+ expect(validation).not.toBeCalled()
+ expect(vm.error).toBe(false)
+ done()
+ })
+ })
+ })
+ })
+})
diff --git a/test/unit/forms/__snapshots__/DateInput.spec.js.snap b/test/unit/forms/__snapshots__/DateInput.spec.js.snap
new file mode 100644
index 0000000..2278c3e
--- /dev/null
+++ b/test/unit/forms/__snapshots__/DateInput.spec.js.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Date Input should match the snapshot 1`] = `
+
+
+
+`;