diff --git a/ts/components/CaptionEditor.md b/ts/components/CaptionEditor.md
deleted file mode 100644
index 4da5142a04..0000000000
--- a/ts/components/CaptionEditor.md
+++ /dev/null
@@ -1,76 +0,0 @@
-## Image
-
-```js
-let caption = null;
-
-
- console.log('onSave', caption)}
- close={() => console.log('close')}
- i18n={util.i18n}
- />
-
;
-```
-
-## Image with caption
-
-```js
-let caption =
- "This is the user-provided caption. We show it overlaid on the image. If it's really long, then it wraps, but it doesn't get too close to the edges of the image.";
-
-
- console.log('onSave', caption)}
- close={() => console.log('close')}
- i18n={util.i18n}
- />
-
;
-```
-
-## Video
-
-```js
-let caption = null;
-
-
- console.log('onSave', caption)}
- close={() => console.log('close')}
- i18n={util.i18n}
- />
-
;
-```
-
-## Video with caption
-
-```js
-let caption =
- "This is the user-provided caption. We show it overlaid on the image. If it's really long, then it wraps, but it doesn't get too close to the edges of the image.";
-
-
- console.log('onSave', caption)}
- close={() => console.log('close')}
- i18n={util.i18n}
- />
-
;
-```
diff --git a/ts/components/CaptionEditor.stories.tsx b/ts/components/CaptionEditor.stories.tsx
new file mode 100644
index 0000000000..7c391a00cd
--- /dev/null
+++ b/ts/components/CaptionEditor.stories.tsx
@@ -0,0 +1,91 @@
+import * as React from 'react';
+
+import { storiesOf } from '@storybook/react';
+import { text } from '@storybook/addon-knobs';
+import { action } from '@storybook/addon-actions';
+
+import { CaptionEditor, Props } from './CaptionEditor';
+import { AUDIO_MP3, IMAGE_JPEG, VIDEO_MP4 } from '../types/MIME';
+
+// @ts-ignore
+import { setup as setupI18n } from '../../js/modules/i18n';
+
+// @ts-ignore
+import enMessages from '../../_locales/en/messages.json';
+
+const i18n = setupI18n('en', enMessages);
+
+const stories = storiesOf('Components/Caption Editor', module);
+
+const createProps = (overrideProps: Partial = {}): Props => ({
+ attachment: {
+ contentType: IMAGE_JPEG,
+ fileName: '',
+ url: '',
+ ...overrideProps.attachment,
+ },
+ caption: text('caption', overrideProps.caption || ''),
+ close: action('close'),
+ i18n,
+ onSave: action('onSave'),
+ url: text('url', overrideProps.url || ''),
+});
+
+stories.add('Image', () => {
+ const props = createProps({
+ url: '/fixtures/tina-rolf-269345-unsplash.jpg',
+ });
+
+ return ;
+});
+
+stories.add('Image with Caption', () => {
+ const props = createProps({
+ caption:
+ 'This is the user-provided caption. We show it overlaid on the image. If it is really long, then it wraps, but it does not get too close to the edges of the image.',
+ url: '/fixtures/tina-rolf-269345-unsplash.jpg',
+ });
+
+ return ;
+});
+
+stories.add('Video', () => {
+ const props = createProps({
+ attachment: {
+ contentType: VIDEO_MP4,
+ fileName: 'pixabay-Soap-Bubble-7141.mp4',
+ url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
+ },
+ url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
+ });
+
+ return ;
+});
+
+stories.add('Video with Caption', () => {
+ const props = createProps({
+ attachment: {
+ contentType: VIDEO_MP4,
+ fileName: 'pixabay-Soap-Bubble-7141.mp4',
+ url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
+ },
+ caption:
+ 'This is the user-provided caption. We show it overlaid on the image. If it is really long, then it wraps, but it does not get too close to the edges of the image.',
+ url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
+ });
+
+ return ;
+});
+
+stories.add('Unsupported Attachment Type', () => {
+ const props = createProps({
+ attachment: {
+ contentType: AUDIO_MP3,
+ fileName: 'incompetech-com-Agnus-Dei-X.mp3',
+ url: '/fixtures/incompetech-com-Agnus-Dei-X.mp3',
+ },
+ url: '/fixtures/incompetech-com-Agnus-Dei-X.mp3',
+ });
+
+ return ;
+});
diff --git a/ts/components/CaptionEditor.tsx b/ts/components/CaptionEditor.tsx
index 9da7ca9b35..af33dda788 100644
--- a/ts/components/CaptionEditor.tsx
+++ b/ts/components/CaptionEditor.tsx
@@ -7,7 +7,7 @@ import { AttachmentType } from '../types/Attachment';
import { LocalizerType } from '../types/Util';
-interface Props {
+export interface Props {
attachment: AttachmentType;
i18n: LocalizerType;
url: string;