diff --git a/app/components/Project.js b/app/components/Project.js
index 97aabd326e27f8cc16683161db45c65f4a8f4ebb..69766dc996e8adfe4751eebec143b797c6a133e8 100644
--- a/app/components/Project.js
+++ b/app/components/Project.js
@@ -1,100 +1,21 @@
 import React from 'react'
 import PropTypes from 'prop-types'
-import { connect } from 'react-redux'
-import { browserHistory, Link } from 'react-router'
-import { Button } from 'react-bootstrap'
-import { deleteCollection, getCollection } from 'pubsweet-client/src/actions/collections'
-import { getFragments } from 'pubsweet-client/src/actions/fragments'
 import './Project.css'
-import RolesSummary from './RolesSummary'
+import { Link } from 'react-router'
 
-class Project extends React.Component {
-  componentDidMount () {
-    const { params } = this.props
+const Project = ({ children, project }) => (
+  <div>
+    <div className="project-title">
+      <Link to={`/projects/${project.id}`}>{project.title}</Link>
+    </div>
 
-    this.fetch(params.project)
-  }
-
-  componentWillReceiveProps (nextProps) {
-    const { params } = nextProps
-
-    if (params.project !== this.props.params.project) {
-      this.fetch(params.project)
-    }
-  }
-
-  fetch (id) {
-    const { getCollection, getFragments } = this.props
-
-    getCollection({ id })
-    getFragments({ id }, {
-      fields: ['version', 'submitted']
-    })
-  }
-
-  remove = () => {
-    const { project, deleteCollection } = this.props
-
-    if (!window.confirm('Delete this submission?')) {
-      return
-    }
-
-    deleteCollection(project).then(() => {
-      browserHistory.push('/')
-    })
-  }
-
-  render () {
-    const { project, children } = this.props
-
-    if (!project) return null
-
-    // TODO: how to ensure that user info is loaded for each role?
-
-    return (
-      <div className="content-text main" style={{paddingBottom: 90}}>
-        <div className="container">
-          <Button bsSize="small" bsStyle="link" onClick={this.remove} style={{ color: '#eee', background: 'none', position: 'fixed', top: 50, right: 50 }}><span className="fa fa-remove"/></Button>
-
-          <div className="project-title">
-            <Link to={`/projects/${project.id}`}>{project.title}</Link>
-          </div>
-
-          <div style={{ display: 'flex' }}>
-            <div style={{ flex: 1 }}>
-              {children}
-            </div>
-
-            <div className="content-metadata" style={{ width: 200 }}>
-              {project.roles && (
-                <RolesSummary project={project}/>
-              )}
-            </div>
-          </div>
-        </div>
-      </div>
-    )
-  }
-}
+    {children}
+  </div>
+)
 
 Project.propTypes = {
   children: PropTypes.node,
-  params: PropTypes.object.isRequired,
-  project: PropTypes.object,
-  getFragments: PropTypes.func.isRequired,
-  deleteCollection: PropTypes.func.isRequired,
-  getCollection: PropTypes.func.isRequired
+  project: PropTypes.object.isRequired
 }
 
-export default connect(
-  (state, ownProps) => ({
-    project: state.collections.find(collection => {
-      return collection.id === ownProps.params.project
-    })
-  }),
-  {
-    getFragments,
-    deleteCollection,
-    getCollection
-  }
-)(Project)
+export default Project
diff --git a/app/components/RemoveProject.js b/app/components/RemoveProject.js
new file mode 100644
index 0000000000000000000000000000000000000000..9062f2b6d5da9d3a18ea073d1c1282c433c76d53
--- /dev/null
+++ b/app/components/RemoveProject.js
@@ -0,0 +1,16 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import { Button } from 'react-bootstrap'
+
+const RemoveProject = ({ onClick }) => (
+  <Button bsSize="small" bsStyle="link" onClick={onClick}
+          style={{ color: '#eee', background: 'none', position: 'fixed', top: 50, right: 50 }}>
+    <span className="fa fa-remove"/>
+  </Button>
+)
+
+RemoveProject.propTypes = {
+  onClick: PropTypes.func.isRequired
+}
+
+export default RemoveProject
diff --git a/app/components/RolesSummary.js b/app/components/RolesSummary.js
index 5ad7f15d4e88c5ad665ff4f8b0e78c87a76ea530..8f8732c883d9585668f122e1121abd7707e1cdf7 100644
--- a/app/components/RolesSummary.js
+++ b/app/components/RolesSummary.js
@@ -1,8 +1,6 @@
 import React from 'react'
 import PropTypes from 'prop-types'
-import { Link } from 'react-router'
-import { connect } from 'react-redux'
-import RolesSummaryItem from './RolesSummaryItem'
+import RolesSummaryItemContainer from '../containers/RolesSummaryItemContainer'
 
 const roleTypes = ['owner', 'editor', 'reviewer']
 
@@ -19,7 +17,7 @@ const RolesSummary = ({ project }) => (
           const role = roles[id]
 
           return (
-            <RolesSummaryItem key={id} roleId={id} roleType={roleType} project={project} role={role}/>
+            <RolesSummaryItemContainer key={id} roleId={id} roleType={roleType} project={project} role={role}/>
           )
         })
       })}
@@ -32,4 +30,4 @@ RolesSummary.propTypes = {
   project: PropTypes.object.isRequired
 }
 
-export default connect()(RolesSummary)
+export default RolesSummary
diff --git a/app/components/RolesSummaryItem.js b/app/components/RolesSummaryItem.js
index d7aefb5eb0152d3e6d46b48179765b0039f1adcf..8989be9b3de0cdc5666deb8be9eb2c7e9fa96902 100644
--- a/app/components/RolesSummaryItem.js
+++ b/app/components/RolesSummaryItem.js
@@ -1,68 +1,24 @@
 import React from 'react'
 import PropTypes from 'prop-types'
-import { connect } from 'react-redux'
-import { getUser } from 'pubsweet-client/src/actions/users'
 import { Link } from 'react-router'
 
-const ucfirst = (text) => {
-  return text.substr(0, 1).toUpperCase() + text.substr(1)
-}
-
-class RolesSummaryItem extends React.Component {
-  componentDidMount () {
-    const userId = this.props.role.user.id
-
-    if (userId) {
-      this.fetch(userId)
-    }
-  }
-
-  componentWillReceiveProps (nextProps) {
-    const userId = nextProps.role.user.id
-
-    if (userId && userId !== this.props.role.user.id) {
-      this.fetch(userId)
-    }
-  }
-
-  fetch (id) {
-    this.props.getUser({ id })
-  }
-
-  render () {
-    const { project, roleId, roleType, user } = this.props
-
-    if (!user) return null
-
-    return (
-      <div style={{ display: 'table-row' }}>
-        <div style={{ display: 'table-cell', padding: '2px 5px 2px 15px', color: '#4990E2' }}>
-          {ucfirst(roleType)}
-        </div>
-        <div style={{ display: 'table-cell', padding: '2px 5px' }}>
-          <Link to={`/projects/${project.id}/roles/${roleType}/${roleId}`}>
-            {user.name || user.username}
-          </Link>
-        </div>
-      </div>
-    )
-  }
-}
+const RolesSummaryItem = ({ label, url, user }) => (
+  <div style={{ display: 'table-row' }}>
+    <div style={{ display: 'table-cell', padding: '2px 5px 2px 15px', color: '#4990E2' }}>
+      {label}
+    </div>
+    <div style={{ display: 'table-cell', padding: '2px 5px' }}>
+      <Link to={url}>
+        {user.name || user.username}
+      </Link>
+    </div>
+  </div>
+)
 
 RolesSummaryItem.propTypes = {
-  getUser: PropTypes.func.isRequired,
-  roleId: PropTypes.string.isRequired,
-  roleType: PropTypes.string.isRequired,
-  project: PropTypes.object.isRequired,
-  role: PropTypes.object.isRequired,
-  user: PropTypes.object
+  label: PropTypes.string.isRequired,
+  url: PropTypes.string.isRequired,
+  user: PropTypes.object.isRequired
 }
 
-export default connect(
-  (state, ownProps) => ({
-    user: ownProps.role.user.id ? state.users.users.find(user => user.id === ownProps.role.user.id) : ownProps.role.user
-  }),
-  {
-    getUser
-  }
-)(RolesSummaryItem)
+export default RolesSummaryItem
diff --git a/app/containers/ProjectContainer.js b/app/containers/ProjectContainer.js
new file mode 100644
index 0000000000000000000000000000000000000000..a9d83142b3386296cf2809179c1380e35a8314e6
--- /dev/null
+++ b/app/containers/ProjectContainer.js
@@ -0,0 +1,99 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import { connect } from 'react-redux'
+import { push } from 'react-router-redux'
+import { deleteCollection, getCollection } from 'pubsweet-client/src/actions/collections'
+import { getFragments } from 'pubsweet-client/src/actions/fragments'
+import Project from '../components/Project'
+import RemoveProject from '../components/RemoveProject'
+import RolesSummary from '../components/RolesSummary'
+
+class ProjectContainer extends React.Component {
+  componentDidMount () {
+    const { params } = this.props
+
+    this.fetch(params.project)
+  }
+
+  componentWillReceiveProps (nextProps) {
+    const { params } = nextProps
+
+    if (params.project !== this.props.params.project) {
+      this.fetch(params.project)
+    }
+  }
+
+  fetch (id) {
+    const { getCollection, getFragments } = this.props
+
+    getCollection({ id })
+
+    getFragments({ id }, {
+      fields: ['version', 'submitted']
+    })
+  }
+
+  remove = () => {
+    const { project, deleteCollection, push } = this.props
+
+    if (!window.confirm('Delete this submission?')) {
+      return
+    }
+
+    deleteCollection(project).then(() => {
+      push('/')
+    })
+  }
+
+  render () {
+    const { project, children } = this.props
+
+    if (!project) return null
+
+    return (
+      <div className="content-text main" style={{ paddingBottom: 90 }}>
+        <div className="container">
+          <RemoveProject onClick={this.remove}/>
+
+          <div style={{ display: 'flex' }}>
+            <div style={{ flex: 1 }}>
+              <Project project={project}>
+                {children}
+              </Project>
+            </div>
+
+            <div className="content-metadata" style={{ width: 200 }}>
+              {project.roles && (
+                <RolesSummary project={project}/>
+              )}
+            </div>
+          </div>
+        </div>
+      </div>
+    )
+  }
+}
+
+ProjectContainer.propTypes = {
+  children: PropTypes.node,
+  params: PropTypes.object.isRequired,
+  project: PropTypes.object,
+  push: PropTypes.func.isRequired,
+  getFragments: PropTypes.func.isRequired,
+  deleteCollection: PropTypes.func.isRequired,
+  getCollection: PropTypes.func.isRequired
+}
+
+export default connect(
+  (state, ownProps) => ({
+    project: state.collections.find(collection => {
+      return collection.id === ownProps.params.project
+    })
+  }),
+  {
+    getFragments,
+    deleteCollection,
+    getCollection,
+    push
+  }
+)(ProjectContainer)
diff --git a/app/containers/RolesSummaryItemContainer.js b/app/containers/RolesSummaryItemContainer.js
new file mode 100644
index 0000000000000000000000000000000000000000..41aafc87e1886e74a7976e917549e8abd6c30a61
--- /dev/null
+++ b/app/containers/RolesSummaryItemContainer.js
@@ -0,0 +1,59 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import { connect } from 'react-redux'
+import { getUser } from 'pubsweet-client/src/actions/users'
+import RolesSummaryItem from '../components/RolesSummaryItem'
+
+const ucfirst = (text) => {
+  return text.substr(0, 1).toUpperCase() + text.substr(1)
+}
+
+class RolesSummaryItemContainer extends React.Component {
+  componentDidMount () {
+    const userId = this.props.role.user.id
+
+    if (userId) {
+      this.fetch(userId)
+    }
+  }
+
+  componentWillReceiveProps (nextProps) {
+    const userId = nextProps.role.user.id
+
+    if (userId && userId !== this.props.role.user.id) {
+      this.fetch(userId)
+    }
+  }
+
+  fetch (id) {
+    this.props.getUser({ id })
+  }
+
+  render () {
+    const { project, roleId, roleType, user } = this.props
+
+    if (!user) return null
+
+    return (
+      <RolesSummaryItem label={ucfirst(roleType)} user={user} link={`/projects/${project.id}/roles/${roleType}/${roleId}`}/>
+    )
+  }
+}
+
+RolesSummaryItemContainer.propTypes = {
+  getUser: PropTypes.func.isRequired,
+  roleId: PropTypes.string.isRequired,
+  roleType: PropTypes.string.isRequired,
+  project: PropTypes.object.isRequired,
+  role: PropTypes.object.isRequired,
+  user: PropTypes.object
+}
+
+export default connect(
+  (state, ownProps) => ({
+    user: ownProps.role.user.id ? state.users.users.find(user => user.id === ownProps.role.user.id) : ownProps.role.user
+  }),
+  {
+    getUser
+  }
+)(RolesSummaryItemContainer)
diff --git a/app/routes.jsx b/app/routes.jsx
index 6eb3814a76875c5eaa69d7e6d607fb34c902b75d..103359df56de5e2cfcc095f9ffe57b3d8b3dafb3 100644
--- a/app/routes.jsx
+++ b/app/routes.jsx
@@ -15,9 +15,9 @@ export default (
 
     <Route path="/" component={App}>
       <Route component={AuthenticatedContainer}>
-        <Route path="projects" component={chunk(import('./components/ProjectList'))}/>
+        <Route path="projects" component={chunk(import('./containers/ProjectListContainer'))}/>
 
-        <Route path="projects/:project" component={chunk(import('./components/Project'))}>
+        <Route path="projects/:project" component={chunk(import('./containers/ProjectContainer'))}>
           <IndexRoute component={chunk(import('./components/Snapshots'))}/>
 
           <Route path="declarations" component={chunk(import('./components/Declarations'))}/>
diff --git a/stories/index.js b/stories/index.js
index 34d9f5a759d8c333bc12082337b2939adea111d9..feefa38021d9d138cce52e1c989fa9194ea4ff74 100644
--- a/stories/index.js
+++ b/stories/index.js
@@ -14,19 +14,41 @@ import projects from './data/projects'
 
 import Upload from '../app/components/Upload'
 import ProjectList from '../app/components/ProjectList'
+import Project from '../app/components/Project'
+import RemoveProject from '../app/components/RemoveProject'
+import RolesSummaryItem from '../app/components/RolesSummaryItem'
 
 // storiesOf('Welcome', module)
 //   .add('to Storybook', () => <Welcome showApp={linkTo('Button')} />)
 
+const project = projects[0]
+
 storiesOf('Upload', module)
   .add('dropzone', () => (
-    <Upload onDrop={action('dropped')} ink={{ isFetching: false }}/>
+    <Upload onDrop={action('drop')} ink={{ isFetching: false }}/>
   ))
   .add('converting', () => (
-    <Upload onDrop={action('dropped')} ink={{ isFetching: true }}/>
+    <Upload onDrop={action('drop')} ink={{ isFetching: true }}/>
   ))
 
 storiesOf('ProjectList', module)
   .add('items', () => (
     <ProjectList projects={projects}/>
   ))
+
+storiesOf('Project', module)
+  .add('title', () => (
+    <Project project={project}/>
+  ))
+
+storiesOf('RemoveProject', module)
+  .add('button', () => (
+    <RemoveProject onClick={action('remove')}/>
+  ))
+
+storiesOf('RolesSummaryItem', module)
+  .add('item', () => (
+    <RolesSummaryItem label="Owner" url="#" user={{
+      username: 'foo'
+    }}/>
+  ))