diff --git a/app/assets/javascripts/components/actions/modal.jsx b/app/assets/javascripts/components/actions/modal.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..89dbc79471b92a9a3530048f19b2113dbf2cf38d
--- /dev/null
+++ b/app/assets/javascripts/components/actions/modal.jsx
@@ -0,0 +1,15 @@
+export const MEDIA_OPEN  = 'MEDIA_OPEN';
+export const MODAL_CLOSE = 'MODAL_CLOSE';
+
+export function openMedia(url) {
+  return {
+    type: MEDIA_OPEN,
+    url: url
+  };
+};
+
+export function closeModal() {
+  return {
+    type: MODAL_CLOSE
+  };
+};
diff --git a/app/assets/javascripts/components/components/media_gallery.jsx b/app/assets/javascripts/components/components/media_gallery.jsx
index 432de907463d089dc1d4c7adbf7b3194597562d5..bdb456a08d922bed9d1543e412e82c23b3a5a4b3 100644
--- a/app/assets/javascripts/components/components/media_gallery.jsx
+++ b/app/assets/javascripts/components/components/media_gallery.jsx
@@ -5,11 +5,21 @@ const MediaGallery = React.createClass({
 
   propTypes: {
     media: ImmutablePropTypes.list.isRequired,
-    height: React.PropTypes.number.isRequired
+    height: React.PropTypes.number.isRequired,
+    onOpenMedia: React.PropTypes.func.isRequired
   },
 
   mixins: [PureRenderMixin],
 
+  handleClick (url, e) {
+    if (e.button === 0) {
+      e.preventDefault();
+      this.props.onOpenMedia(url);
+    }
+
+    e.stopPropagation();
+  },
+
   render () {
     var children = this.props.media.take(4);
     var size     = children.size;
@@ -25,7 +35,7 @@ const MediaGallery = React.createClass({
       if (size === 1) {
         width = 100;
       }
-      
+
       if (size === 4 || (size === 3 && i > 0)) {
         height = 50;
       }
@@ -64,7 +74,11 @@ const MediaGallery = React.createClass({
         }
       }
 
-      return <a key={attachment.get('id')} href={attachment.get('url')} target='_blank' style={{ boxSizing: 'border-box', position: 'relative', left: left, top: top, right: right, bottom: bottom, float: 'left', textDecoration: 'none', border: 'none', display: 'block', width: `${width}%`, height: `${height}%`, background: `url(${attachment.get('preview_url')}) no-repeat center`, backgroundSize: 'cover', cursor: 'zoom-in' }} />;
+      return (
+        <div key={attachment.get('id')} style={{ boxSizing: 'border-box', position: 'relative', left: left, top: top, right: right, bottom: bottom, float: 'left', border: 'none', display: 'block', width: `${width}%`, height: `${height}%` }}>
+          <a href={attachment.get('url')} onClick={this.handleClick.bind(this, attachment.get('url'))} target='_blank' style={{ display: 'block', width: '100%', height: '100%', background: `url(${attachment.get('preview_url')}) no-repeat center`, textDecoration: 'none', backgroundSize: 'cover', cursor: 'zoom-in' }} />
+        </div>
+      );
     });
 
     return (
diff --git a/app/assets/javascripts/components/components/status.jsx b/app/assets/javascripts/components/components/status.jsx
index 8855c6c12fd3fb82d478a520d2be5aaa6e529efb..3fdb9a80c1d1498d0be76270f655d9481980ef13 100644
--- a/app/assets/javascripts/components/components/status.jsx
+++ b/app/assets/javascripts/components/components/status.jsx
@@ -21,6 +21,7 @@ const Status = React.createClass({
     onFavourite: React.PropTypes.func,
     onReblog: React.PropTypes.func,
     onDelete: React.PropTypes.func,
+    onOpenMedia: React.PropTypes.func,
     me: React.PropTypes.number
   },
 
@@ -67,7 +68,7 @@ const Status = React.createClass({
       if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
         media = <VideoPlayer media={status.getIn(['media_attachments', 0])} />;
       } else {
-        media = <MediaGallery media={status.get('media_attachments')} height={110} />;
+        media = <MediaGallery media={status.get('media_attachments')} height={110} onOpenMedia={this.props.onOpenMedia} />;
       }
     }
 
diff --git a/app/assets/javascripts/components/containers/status_container.jsx b/app/assets/javascripts/components/containers/status_container.jsx
index b4d3740d9c96a554794803385023b47dd04bc1e9..0f4b8ee164c19a97f5dd8786dbddec9234b9463c 100644
--- a/app/assets/javascripts/components/containers/status_container.jsx
+++ b/app/assets/javascripts/components/containers/status_container.jsx
@@ -12,6 +12,7 @@ import {
   unfavourite
 }                        from '../actions/interactions';
 import { deleteStatus }  from '../actions/statuses';
+import { openMedia }     from '../actions/modal';
 
 const makeMapStateToProps = () => {
   const getStatus = makeGetStatus();
@@ -52,6 +53,10 @@ const mapDispatchToProps = (dispatch) => ({
 
   onMention (account) {
     dispatch(mentionCompose(account));
+  },
+
+  onOpenMedia (url) {
+    dispatch(openMedia(url));
   }
 
 });
diff --git a/app/assets/javascripts/components/features/status/components/detailed_status.jsx b/app/assets/javascripts/components/features/status/components/detailed_status.jsx
index ffa536ae8e5acd910980bff1972b03c1881e029f..9f8e9b6cc21b057af9786d4edc9bb341dc80e1c5 100644
--- a/app/assets/javascripts/components/features/status/components/detailed_status.jsx
+++ b/app/assets/javascripts/components/features/status/components/detailed_status.jsx
@@ -14,7 +14,8 @@ const DetailedStatus = React.createClass({
   },
 
   propTypes: {
-    status: ImmutablePropTypes.map.isRequired
+    status: ImmutablePropTypes.map.isRequired,
+    onOpenMedia: React.PropTypes.func.isRequired
   },
 
   mixins: [PureRenderMixin],
@@ -36,7 +37,7 @@ const DetailedStatus = React.createClass({
       if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
         media = <VideoPlayer media={status.getIn(['media_attachments', 0])} width={317} height={178} />;
       } else {
-        media = <MediaGallery media={status.get('media_attachments')} height={300} />;
+        media = <MediaGallery media={status.get('media_attachments')} height={300} onOpenMedia={this.props.onOpenMedia} />;
       }
     }
 
diff --git a/app/assets/javascripts/components/features/status/index.jsx b/app/assets/javascripts/components/features/status/index.jsx
index f4ca8ff92c6a87648529510b21bbd0bf822009fe..dc29a87c78678dd414fd53842e41f1cb930b15d8 100644
--- a/app/assets/javascripts/components/features/status/index.jsx
+++ b/app/assets/javascripts/components/features/status/index.jsx
@@ -22,6 +22,7 @@ import {
 import { ScrollContainer }   from 'react-router-scroll';
 import ColumnBackButton      from '../../components/column_back_button';
 import StatusContainer       from '../../containers/status_container';
+import { openMedia }         from '../../actions/modal';
 
 const makeMapStateToProps = () => {
   const getStatus = makeGetStatus();
@@ -78,6 +79,10 @@ const Status = React.createClass({
     this.props.dispatch(mentionCompose(account));
   },
 
+  handleOpenMedia (url) {
+    this.props.dispatch(openMedia(url));
+  },
+
   renderChildren (list) {
     return list.map(id => <StatusContainer key={id} id={id} />);
   },
@@ -112,7 +117,7 @@ const Status = React.createClass({
           <div style={{ overflowY: 'scroll', flex: '1 1 auto' }} className='scrollable'>
             {ancestors}
 
-            <DetailedStatus status={status} me={me} />
+            <DetailedStatus status={status} me={me} onOpenMedia={this.handleOpenMedia} />
             <ActionBar status={status} me={me} onReply={this.handleReplyClick} onFavourite={this.handleFavouriteClick} onReblog={this.handleReblogClick} onDelete={this.handleDeleteClick} onMention={this.handleMentionClick} />
 
             {descendants}
diff --git a/app/assets/javascripts/components/features/ui/containers/modal_container.jsx b/app/assets/javascripts/components/features/ui/containers/modal_container.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..323125e3028eac1b75df775c4a6ba243376cdce9
--- /dev/null
+++ b/app/assets/javascripts/components/features/ui/containers/modal_container.jsx
@@ -0,0 +1,67 @@
+import { connect }           from 'react-redux';
+import { SkyLightStateless } from 'react-skylight';
+import { closeModal }        from '../../../actions/modal';
+
+const mapStateToProps = state => ({
+  url: state.getIn(['modal', 'url']),
+  isVisible: state.getIn(['modal', 'open'])
+});
+
+const mapDispatchToProps = dispatch => ({
+  onCloseClicked () {
+    dispatch(closeModal());
+  },
+
+  onOverlayClicked () {
+    dispatch(closeModal());
+  }
+});
+
+const styles = {
+  overlayStyles: {
+
+  },
+
+  dialogStyles: {
+    width: '600px',
+    color: '#282c37',
+    fontSize: '16px',
+    lineHeight: '37px',
+    marginTop: '-300px',
+    left: '0',
+    right: '0',
+    marginLeft: 'auto',
+    marginRight: 'auto',
+    height: 'auto'
+  },
+
+  imageStyle: {
+    display: 'block',
+    maxWidth: '100%',
+    height: 'auto',
+    margin: '0 auto'
+  }
+};
+
+const Modal = React.createClass({
+
+  propTypes: {
+    url: React.PropTypes.string,
+    isVisible: React.PropTypes.bool,
+    onCloseClicked: React.PropTypes.func,
+    onOverlayClicked: React.PropTypes.func
+  },
+
+  render () {
+    const { url, ...other } = this.props;
+
+    return (
+      <SkyLightStateless {...other} dialogStyles={styles.dialogStyles} overlayStyles={styles.overlayStyles}>
+        <img src={url} style={styles.imageStyle} />
+      </SkyLightStateless>
+    );
+  }
+
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(Modal);
diff --git a/app/assets/javascripts/components/features/ui/index.jsx b/app/assets/javascripts/components/features/ui/index.jsx
index 06a9d2f509dbc57ec7b111e0e1f7e2520be52236..655b1e2ee7522d40db3af451994579a67fa8e4c9 100644
--- a/app/assets/javascripts/components/features/ui/index.jsx
+++ b/app/assets/javascripts/components/features/ui/index.jsx
@@ -7,6 +7,7 @@ import MentionsTimeline       from '../mentions_timeline';
 import Compose                from '../compose';
 import MediaQuery             from 'react-responsive';
 import TabsBar                from './components/tabs_bar';
+import ModalContainer         from './containers/modal_container';
 
 const UI = React.createClass({
 
@@ -36,6 +37,7 @@ const UI = React.createClass({
 
         <NotificationsContainer />
         <LoadingBarContainer style={{ backgroundColor: '#2b90d9', left: '0', top: '0' }} />
+        <ModalContainer />
       </div>
     );
   }
diff --git a/app/assets/javascripts/components/reducers/index.jsx b/app/assets/javascripts/components/reducers/index.jsx
index da9ab1a21a7eadecd6804898b06657804f13323f..e9256b8ec80666ee439afc0cc389e8df0f0be297 100644
--- a/app/assets/javascripts/components/reducers/index.jsx
+++ b/app/assets/javascripts/components/reducers/index.jsx
@@ -5,6 +5,7 @@ import compose               from './compose';
 import follow                from './follow';
 import notifications         from './notifications';
 import { loadingBarReducer } from 'react-redux-loading-bar';
+import modal                 from './modal';
 
 export default combineReducers({
   timelines,
@@ -13,4 +14,5 @@ export default combineReducers({
   follow,
   notifications,
   loadingBar: loadingBarReducer,
+  modal,
 });
diff --git a/app/assets/javascripts/components/reducers/modal.jsx b/app/assets/javascripts/components/reducers/modal.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..b529b6aa8f1c6c4b97c208c64f582d936adf1d98
--- /dev/null
+++ b/app/assets/javascripts/components/reducers/modal.jsx
@@ -0,0 +1,21 @@
+import { MEDIA_OPEN, MODAL_CLOSE } from '../actions/modal';
+import Immutable                   from 'immutable';
+
+const initialState = Immutable.Map({
+  url: '',
+  open: false
+});
+
+export default function modal(state = initialState, action) {
+  switch(action.type) {
+    case MEDIA_OPEN:
+      return state.withMutations(map => {
+        map.set('url', action.url);
+        map.set('open', true);
+      });
+    case MODAL_CLOSE:
+      return state.set('open', false);
+    default:
+      return state;
+  }
+};
diff --git a/package.json b/package.json
index 78560f717213279197c8614acf8749f77dd21691..558e565415af41e2140bb201ba85f3f16a9452d6 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
   },
   "dependencies": {
     "react-responsive": "^1.1.5",
-    "react-router-scroll": "^0.3.2"
+    "react-router-scroll": "^0.3.2",
+    "react-skylight": "^0.4.1"
   }
 }
diff --git a/yarn.lock b/yarn.lock
index 6ee2398186fdaaf8f6f321da78126c7aa1d36569..766ca3114268174a512c0f4184ef06be756fddf9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3927,6 +3927,10 @@ react-simple-dropdown@^1.1.4:
   dependencies:
     classnames "^2.1.2"
 
+react-skylight:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/react-skylight/-/react-skylight-0.4.1.tgz#07d1af6dea0a50a5d8122a786a8ce8bc6bdf2241"
+
 react@^15.3.2:
   version "15.3.2"
   resolved "https://registry.yarnpkg.com/react/-/react-15.3.2.tgz#a7bccd2fee8af126b0317e222c28d1d54528d09e"