diff --git a/ts/components/conversation/media-gallery/MediaGridItem.md b/ts/components/conversation/media-gallery/MediaGridItem.md
deleted file mode 100644
index 842d6bb0a3..0000000000
--- a/ts/components/conversation/media-gallery/MediaGridItem.md
+++ /dev/null
@@ -1,94 +0,0 @@
-#### With image
-
-```jsx
-const mediaItem = {
- thumbnailObjectUrl: 'https://placekitten.com/76/67',
- contentType: 'image/jpeg',
- attachment: {
- fileName: 'foo.jpg',
- contentType: 'image/jpeg',
- },
-};
-;
-```
-
-#### With video
-
-```jsx
-const mediaItem = {
- thumbnailObjectUrl: 'https://placekitten.com/76/67',
- contentType: 'video/mp4',
- attachment: {
- fileName: 'foo.jpg',
- contentType: 'video/mp4',
- },
-};
-;
-```
-
-#### Missing image
-
-```jsx
-const mediaItem = {
- contentType: 'image/jpeg',
- attachment: {
- fileName: 'foo.jpg',
- contentType: 'image/jpeg',
- },
-};
-;
-```
-
-#### Missing video
-
-```jsx
-const mediaItem = {
- contentType: 'video/mp4',
- attachment: {
- fileName: 'foo.jpg',
- contentType: 'video/mp4',
- },
-};
-;
-```
-
-#### Image thumbnail failed to load
-
-```jsx
-const mediaItem = {
- thumbnailObjectUrl: 'nonexistent',
- contentType: 'image/jpeg',
- attachment: {
- fileName: 'foo.jpg',
- contentType: 'image/jpeg',
- },
-};
-;
-```
-
-#### Video thumbnail failed to load
-
-```jsx
-const mediaItem = {
- thumbnailObjectUrl: 'nonexistent',
- contentType: 'video/mp4',
- attachment: {
- fileName: 'foo.jpg',
- contentType: 'video/mp4',
- },
-};
-;
-```
-
-#### Other contentType
-
-```jsx
-const mediaItem = {
- contentType: 'application/json',
- attachment: {
- fileName: 'foo.jpg',
- contentType: 'application/json',
- },
-};
-;
-```
diff --git a/ts/components/conversation/media-gallery/MediaGridItem.stories.tsx b/ts/components/conversation/media-gallery/MediaGridItem.stories.tsx
new file mode 100644
index 0000000000..14fd37757c
--- /dev/null
+++ b/ts/components/conversation/media-gallery/MediaGridItem.stories.tsx
@@ -0,0 +1,134 @@
+import * as React from 'react';
+import { storiesOf } from '@storybook/react';
+import { text, withKnobs } from '@storybook/addon-knobs';
+import { action } from '@storybook/addon-actions';
+
+// @ts-ignore
+import { setup as setupI18n } from '../../../../js/modules/i18n';
+// @ts-ignore
+import enMessages from '../../../../_locales/en/messages.json';
+
+import { MediaItemType } from '../../LightboxGallery';
+import { AttachmentType } from '../../../types/Attachment';
+import { MIMEType } from '../../../types/MIME';
+
+import { MediaGridItem, Props } from './MediaGridItem';
+import { Message } from './types/Message';
+
+const i18n = setupI18n('en', enMessages);
+
+const story = storiesOf(
+ 'Components/Conversation/MediaGallery/MediaGridItem',
+ module
+);
+
+story.addDecorator((withKnobs as any)({ escapeHTML: false }));
+
+const createProps = (
+ overrideProps: Partial & { mediaItem: MediaItemType }
+): Props => ({
+ i18n,
+ mediaItem: overrideProps.mediaItem,
+ onClick: action('onClick'),
+});
+
+const createMediaItem = (
+ overrideProps: Partial = {}
+): MediaItemType => ({
+ thumbnailObjectUrl: text(
+ 'thumbnailObjectUrl',
+ overrideProps.thumbnailObjectUrl || ''
+ ),
+ contentType: text('contentType', overrideProps.contentType || '') as MIMEType,
+ index: 0,
+ attachment: {} as AttachmentType, // attachment not useful in the component
+ message: {} as Message, // message not used in the component
+});
+
+story.add('Image', () => {
+ const mediaItem = createMediaItem({
+ thumbnailObjectUrl: '/fixtures/kitten-1-64-64.jpg',
+ contentType: 'image/jpeg' as MIMEType,
+ });
+
+ const props = createProps({
+ mediaItem,
+ });
+
+ return ;
+});
+
+story.add('Video', () => {
+ const mediaItem = createMediaItem({
+ thumbnailObjectUrl: '/fixtures/kitten-2-64-64.jpg',
+ contentType: 'video/mp4' as MIMEType,
+ });
+
+ const props = createProps({
+ mediaItem,
+ });
+
+ return ;
+});
+
+story.add('Missing Image', () => {
+ const mediaItem = createMediaItem({
+ contentType: 'image/jpeg' as MIMEType,
+ });
+
+ const props = createProps({
+ mediaItem,
+ });
+
+ return ;
+});
+
+story.add('Missing Video', () => {
+ const mediaItem = createMediaItem({
+ contentType: 'video/mp4' as MIMEType,
+ });
+
+ const props = createProps({
+ mediaItem,
+ });
+
+ return ;
+});
+
+story.add('Broken Image', () => {
+ const mediaItem = createMediaItem({
+ thumbnailObjectUrl: '/missing-fixtures/nope.jpg',
+ contentType: 'image/jpeg' as MIMEType,
+ });
+
+ const props = createProps({
+ mediaItem,
+ });
+
+ return ;
+});
+
+story.add('Broken Video', () => {
+ const mediaItem = createMediaItem({
+ thumbnailObjectUrl: '/missing-fixtures/nope.mp4',
+ contentType: 'video/mp4' as MIMEType,
+ });
+
+ const props = createProps({
+ mediaItem,
+ });
+
+ return ;
+});
+
+story.add('Other ContentType', () => {
+ const mediaItem = createMediaItem({
+ contentType: 'application/text' as MIMEType,
+ });
+
+ const props = createProps({
+ mediaItem,
+ });
+
+ return ;
+});
diff --git a/ts/components/conversation/media-gallery/MediaGridItem.tsx b/ts/components/conversation/media-gallery/MediaGridItem.tsx
index 9e010e3002..c2bf7593b1 100644
--- a/ts/components/conversation/media-gallery/MediaGridItem.tsx
+++ b/ts/components/conversation/media-gallery/MediaGridItem.tsx
@@ -8,7 +8,7 @@ import {
import { LocalizerType } from '../../../types/Util';
import { MediaItemType } from '../../LightboxGallery';
-interface Props {
+export interface Props {
mediaItem: MediaItemType;
onClick?: () => void;
i18n: LocalizerType;