diff --git a/src/components/v-notice/index.ts b/src/components/v-notice/index.ts
new file mode 100644
index 0000000000..05b7fcbbf0
--- /dev/null
+++ b/src/components/v-notice/index.ts
@@ -0,0 +1,4 @@
+import VNotice from './v-notice.vue';
+
+export { VNotice };
+export default VNotice;
diff --git a/src/components/v-notice/v-notice.readme.md b/src/components/v-notice/v-notice.readme.md
new file mode 100644
index 0000000000..657a148ec5
--- /dev/null
+++ b/src/components/v-notice/v-notice.readme.md
@@ -0,0 +1,28 @@
+# Notice
+
+```html
+I'm a notice!
+```
+
+## Props
+| Prop | Description | Default |
+|-----------|--------------------------------------------------------------------|---------|
+| `success` | Shows the success notice | `false` |
+| `warning` | Shows the warning notice | `false` |
+| `danger` | Shows the danger notice | `false` |
+| `icon` | Custom icon name, or false if you want to hide the icon completely | `null` |
+
+## Slots
+| Slot | Description | Data |
+|-----------|-------------|------|
+| _default_ | | -- |
+
+## Events
+n/a
+
+## CSS Variables
+| Variable | Default |
+|-------------------------------|----------------------------|
+| `--v-notice-color` | `var(--foreground-color);` |
+| `--v-notice-background-color` | `var(--action-light);` |
+| `--v-notice-icon-color` | `var(--action);` |
diff --git a/src/components/v-notice/v-notice.story.ts b/src/components/v-notice/v-notice.story.ts
new file mode 100644
index 0000000000..23aee2080b
--- /dev/null
+++ b/src/components/v-notice/v-notice.story.ts
@@ -0,0 +1,85 @@
+import {
+ withKnobs,
+ text,
+ boolean,
+ number,
+ color,
+ select,
+ optionsKnob as options
+} from '@storybook/addon-knobs';
+import { action } from '@storybook/addon-actions';
+import Vue from 'vue';
+import VNotice from './v-notice.vue';
+import VIcon from '../v-icon/';
+import markdown from './v-notice.readme.md';
+import withPadding from '../../../.storybook/decorators/with-padding';
+
+Vue.component('v-notice', VNotice);
+Vue.component('v-icon', VIcon);
+
+export default {
+ title: 'Components / Notice',
+ component: VNotice,
+ decorators: [withKnobs, withPadding],
+ parameters: {
+ notes: markdown
+ }
+};
+
+export const withText = () => ({
+ props: {
+ text: {
+ default: text('Text', 'This is a notice')
+ },
+ success: {
+ default: boolean('Success', false)
+ },
+ warning: {
+ default: boolean('Warning', false)
+ },
+ danger: {
+ default: boolean('Danger', false)
+ }
+ },
+ template: `{{text}}`
+});
+
+export const withCustomColors = () => ({
+ props: {
+ color: {
+ default: text('Color', 'red')
+ },
+ backgroundColor: {
+ default: text('Background Color', 'papayawhip')
+ },
+ iconColor: {
+ default: text('Icon Color', 'blue')
+ }
+ },
+ template: `
+ This is a notice
+ `
+});
+
+export const withCustomIcon = () => ({
+ props: {
+ icon: {
+ default: text('Icon', 'translate')
+ }
+ },
+ template: `
+ This is a notice
+ `
+});
+
+export const noIcon = () => ({
+ template: `
+ This is a notice
+ `
+});
diff --git a/src/components/v-notice/v-notice.test.ts b/src/components/v-notice/v-notice.test.ts
new file mode 100644
index 0000000000..b405d48d73
--- /dev/null
+++ b/src/components/v-notice/v-notice.test.ts
@@ -0,0 +1,79 @@
+import { mount, createLocalVue, Wrapper } from '@vue/test-utils';
+import VueCompositionAPI from '@vue/composition-api';
+import VNotice from './v-notice.vue';
+import VIcon from '@/components/v-icon/';
+
+const localVue = createLocalVue();
+localVue.use(VueCompositionAPI);
+localVue.component('v-icon', VIcon);
+
+describe('Notice', () => {
+ let component: Wrapper;
+
+ beforeEach(() => {
+ component = mount(VNotice, {
+ localVue,
+ slots: {
+ default: 'I like pizza'
+ }
+ });
+ });
+
+ it('Renders the default slot in the notice', () => {
+ expect(component.text()).toContain('I like pizza');
+ });
+
+ it('Uses the right color / icon combo for success', async () => {
+ component.setProps({
+ success: true
+ });
+
+ await component.vm.$nextTick();
+
+ expect(component.classes()).toContain('success');
+ expect((component.vm as any).iconName).toBe('check_circle');
+ });
+
+ it('Uses the right color / icon combo for warning', async () => {
+ component.setProps({
+ warning: true
+ });
+
+ await component.vm.$nextTick();
+
+ expect(component.classes()).toContain('warning');
+ expect((component.vm as any).iconName).toBe('warning');
+ });
+
+ it('Uses the right color / icon combo for danger', async () => {
+ component.setProps({
+ danger: true
+ });
+
+ await component.vm.$nextTick();
+
+ expect(component.classes()).toContain('danger');
+ expect((component.vm as any).iconName).toBe('error');
+ });
+
+ it('Defaults to success if all props are given', async () => {
+ component.setProps({
+ success: true,
+ warning: true,
+ danger: true
+ });
+
+ await component.vm.$nextTick();
+
+ expect((component.vm as any).iconName).toBe('check_circle');
+ expect(component.classes()).toContain('success');
+ });
+
+ it('Allows setting a custom icon', async () => {
+ component.setProps({
+ icon: 'person'
+ });
+ await component.vm.$nextTick();
+ expect((component.vm as any).iconName).toBe('person');
+ });
+});
diff --git a/src/components/v-notice/v-notice.vue b/src/components/v-notice/v-notice.vue
new file mode 100644
index 0000000000..9b55a66b5e
--- /dev/null
+++ b/src/components/v-notice/v-notice.vue
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+