diff --git a/__tests__/src/actions/companionWindow.test.js b/__tests__/src/actions/companionWindow.test.js
index 8e41fa4718bc8320271440395764a153a680141d..fd28ad7cd4482b1d8cb511f80e699de1fd1f18f7 100644
--- a/__tests__/src/actions/companionWindow.test.js
+++ b/__tests__/src/actions/companionWindow.test.js
@@ -3,45 +3,51 @@ import ActionTypes from '../../../src/state/actions/action-types';
 
 describe('companionWindow actions', () => {
   describe('addCompanionWindow', () => {
-    it('should create a new companion window with the given options', () => {
-      const options = {
-        id: 'abc123',
-        windowId: 'x',
+    it('should return correct action object', () => {
+      const payload = {
         content: 'info',
         position: 'right',
+        foo: 'bar',
       };
+      const action = actions.addCompanionWindow(payload);
+      expect(action.type).toBe(ActionTypes.ADD_COMPANION_WINDOW);
+      expect(action.payload).toEqual(payload);
+    });
 
-      const expectedAction = {
-        type: ActionTypes.SET_COMPANION_WINDOW,
-        id: 'abc123',
-        windowId: 'x',
-        content: 'info',
-        position: 'right',
-      };
-      expect(actions.addCompanionWindow(options)).toEqual(expectedAction);
+    it('should set the correct default values', () => {
+      const payload = {};
+      const defaults = { foo: 'bar' };
+      const action = actions.addCompanionWindow(payload, defaults);
+      expect(action.payload.foo).toBe('bar');
     });
 
-    it('should generate a new companionWindow ID if one is not provided', () => {
-      const options = {
-        windowId: 'x',
-        content: 'info',
-        position: 'right',
-      };
+    it('should generate a new companionWindow ID', () => {
+      const payload = {};
 
-      expect(actions.addCompanionWindow(options).id).toEqual(
+      expect(actions.addCompanionWindow(payload).id).toEqual(
         expect.stringMatching(/^cw-\w+-\w+/),
       );
     });
   });
 
-  describe('removeCompanionWindow', () => {
-    it('should send the REMOVE_COMPANION_WINDOW action with the given ID', () => {
-      const expectedAction = {
-        type: ActionTypes.REMOVE_COMPANION_WINDOW,
-        id: 'abc123',
+  describe('updateCompanionWindow', () => {
+    it('should return correct action object', () => {
+      const payload = {
+        content: 'info',
+        position: 'right',
       };
+      const action = actions.updateCompanionWindow('cw-123', payload);
+      expect(action.type).toBe(ActionTypes.UPDATE_COMPANION_WINDOW);
+      expect(action.id).toBe('cw-123');
+      expect(action.payload).toEqual(payload);
+    });
+  });
 
-      expect(actions.removeCompanionWindow('abc123')).toEqual(expectedAction);
+  describe('removeCompanionWindow', () => {
+    it('should return correct action object', () => {
+      const action = actions.removeCompanionWindow('cw-123');
+      expect(action.type).toBe(ActionTypes.REMOVE_COMPANION_WINDOW);
+      expect(action.id).toBe('cw-123');
     });
   });
 });
diff --git a/__tests__/src/actions/window.test.js b/__tests__/src/actions/window.test.js
index ec76a792363165102aa1a2fce38b51726a430ba2..2dde5c7c11ba78e4f83b9e9cc8e93b369f3dbf30 100644
--- a/__tests__/src/actions/window.test.js
+++ b/__tests__/src/actions/window.test.js
@@ -27,6 +27,20 @@ describe('window actions', () => {
       expect(actions.addWindow(options)).toEqual(expectedAction);
     });
   });
+
+  describe('updateWindow', () => {
+    it('should return correct action object', () => {
+      const payload = {
+        foo: 1,
+        bar: 2,
+      };
+      const action = actions.updateWindow('window-123', payload);
+      expect(action.type).toBe(ActionTypes.UPDATE_WINDOW);
+      expect(action.id).toBe('window-123');
+      expect(action.payload).toEqual(payload);
+    });
+  });
+
   describe('removeWindow', () => {
     it('removes the window and returns windowId', () => {
       const id = 'abc123';
@@ -88,20 +102,41 @@ describe('window actions', () => {
 
   describe('popOutCompanionWindow', () => {
     it('returns a thunk which dispatches the appropriate actions', () => {
-      const mockDispatch = jest.fn();
+      const mockState = {
+        windows: {
+          abc123: {
+            companionWindowIds: ['cw-1'],
+          },
+        },
+      };
+      const mockDispatch = jest.fn(() => ({ id: 'cw-1' }));
+      const mockGetState = jest.fn(() => mockState);
       const windowId = 'abc123';
       const panelType = 'info';
       const position = 'right';
       const thunk = actions.popOutCompanionWindow(windowId, panelType, position);
 
       expect(typeof thunk).toEqual('function');
-      thunk(mockDispatch);
-      expect(mockDispatch).toHaveBeenCalledTimes(2);
-      const cwId = mockDispatch.mock.calls[0][0].id;
-      expect(mockDispatch).toHaveBeenCalledWith({
-        type: ActionTypes.SET_COMPANION_WINDOW, id: cwId, windowId, content: panelType, position,
+      thunk(mockDispatch, mockGetState);
+      expect(mockDispatch).toHaveBeenCalledTimes(4);
+
+      expect(mockDispatch).toHaveBeenNthCalledWith(1, {
+        type: ActionTypes.REMOVE_COMPANION_WINDOW,
+        id: 'cw-1',
+      });
+
+      const addCompanionWindowAction = mockDispatch.mock.calls[1][0];
+      expect(addCompanionWindowAction.type).toBe(ActionTypes.ADD_COMPANION_WINDOW);
+      expect(addCompanionWindowAction.payload).toEqual({ content: 'info', position: 'right' });
+      expect(addCompanionWindowAction.id.startsWith('cw-')).toBe(true);
+
+      expect(mockDispatch).toHaveBeenNthCalledWith(3, {
+        type: ActionTypes.UPDATE_WINDOW,
+        id: 'abc123',
+        payload: { companionWindowIds: ['cw-1'] },
       });
-      expect(mockDispatch).toHaveBeenCalledWith({
+
+      expect(mockDispatch).toHaveBeenNthCalledWith(4, {
         type: ActionTypes.TOGGLE_WINDOW_SIDE_BAR_PANEL, windowId, panelType: 'closed',
       });
     });
diff --git a/__tests__/src/components/CompanionWindow.test.js b/__tests__/src/components/CompanionWindow.test.js
index 68cc647cf31d2c8973ab1421c402dd477ff9e967..f155abd8ef11cdfcad8ea38296e1f6fee67137bb 100644
--- a/__tests__/src/components/CompanionWindow.test.js
+++ b/__tests__/src/components/CompanionWindow.test.js
@@ -35,7 +35,7 @@ describe('CompanionWindow', () => {
   });
 
   describe('when the close companion window button is clicked', () => {
-    it('triggers the removeCompanionWindow prop with the appropriate args', () => {
+    it('triggers the onCloseClick prop with the appropriate args', () => {
       const removeCompanionWindowEvent = jest.fn();
       companionWindow = createWrapper({
         onCloseClick: removeCompanionWindowEvent,
@@ -44,7 +44,7 @@ describe('CompanionWindow', () => {
       const closeButton = companionWindow.find('WithStyles(IconButton)[aria-label="closeCompanionWindow"]');
       closeButton.simulate('click');
       expect(removeCompanionWindowEvent).toHaveBeenCalledTimes(1);
-      expect(removeCompanionWindowEvent).toHaveBeenCalledWith('abc123', 'x');
+      expect(removeCompanionWindowEvent).toHaveBeenCalledWith('x', 'abc123');
     });
   });
 });
diff --git a/__tests__/src/components/WindowMiddleContent.test.js b/__tests__/src/components/WindowMiddleContent.test.js
index 9088c569704174fd8706a2aa21b71401587a2678..64da2c84b34af25fa14cb51b23809348ef418e74 100644
--- a/__tests__/src/components/WindowMiddleContent.test.js
+++ b/__tests__/src/components/WindowMiddleContent.test.js
@@ -5,24 +5,34 @@ import CompanionWindow from '../../../src/containers/CompanionWindow';
 import WindowSideBar from '../../../src/containers/WindowSideBar';
 import WindowViewer from '../../../src/containers/WindowViewer';
 
+/** create wrapper */
+function createWrapper(props) {
+  return shallow(
+    <WindowMiddleContent
+      companionWindowIds={['cw1', 'cw-2']}
+      window={{ id: 'window-1' }}
+      manifest={{}}
+      {...props}
+    />,
+  );
+}
+
 describe('WindowMiddleContent', () => {
-  let wrapper;
-  let manifest;
   it('should render outer element', () => {
-    wrapper = shallow(<WindowMiddleContent window={window} />);
+    const wrapper = createWrapper();
     expect(wrapper.find('.mirador-window-middle-content')).toHaveLength(1);
   });
-  it('should render <CompanionWindow>', () => {
-    wrapper = shallow(<WindowMiddleContent window={window} rightCompanionWindowId="x" />);
-    expect(wrapper.find(CompanionWindow)).toHaveLength(1);
+  it('should render all <CompanionWindow> components', () => {
+    const wrapper = createWrapper();
+    expect(wrapper.find(CompanionWindow)).toHaveLength(2);
   });
   it('should render <WindowSideBar>', () => {
-    wrapper = shallow(<WindowMiddleContent window={window} />);
+    const wrapper = createWrapper();
     expect(wrapper.find(WindowSideBar)).toHaveLength(1);
   });
   it('should render <WindowViewer> if manifest is present', () => {
-    manifest = { id: 456, isFetching: false };
-    wrapper = shallow(<WindowMiddleContent window={window} manifest={manifest} />);
+    const manifest = { id: 456, isFetching: false };
+    const wrapper = createWrapper({ manifest });
     expect(wrapper.find(WindowViewer)).toHaveLength(1);
   });
 });
diff --git a/__tests__/src/components/WindowTopBar.test.js b/__tests__/src/components/WindowTopBar.test.js
index e482f635c53eeb19ff208026f008458e76c9ef3d..4fe237023b1c07600e28eb782d73d9eea2941d25 100644
--- a/__tests__/src/components/WindowTopBar.test.js
+++ b/__tests__/src/components/WindowTopBar.test.js
@@ -20,7 +20,7 @@ function createWrapper(props) {
       windowId="xyz"
       classes={{}}
       t={str => str}
-      removeWindow={() => {}}
+      closeWindow={() => {}}
       toggleWindowSideBar={() => {}}
       {...props}
     />,
@@ -67,8 +67,8 @@ describe('WindowTopBar', () => {
   });
 
   it('passes correct props to <Button/>', () => {
-    const removeWindow = jest.fn();
-    const wrapper = createWrapper({ removeWindow });
-    expect(wrapper.find(IconButton).last().props().onClick).toBe(removeWindow);
+    const closeWindow = jest.fn();
+    const wrapper = createWrapper({ closeWindow });
+    expect(wrapper.find(IconButton).last().props().onClick).toBe(closeWindow);
   });
 });
diff --git a/__tests__/src/reducers/companionWindows.test.js b/__tests__/src/reducers/companionWindows.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..68775833910068ef0252fdf95084980790c37c1a
--- /dev/null
+++ b/__tests__/src/reducers/companionWindows.test.js
@@ -0,0 +1,63 @@
+import { companionWindowsReducer } from '../../../src/state/reducers/companionWindows';
+import ActionTypes from '../../../src/state/actions/action-types';
+
+describe('companionWindowsReducer', () => {
+  describe('ADD_COMPANION_WINDOW', () => {
+    it('adds a new companion window', () => {
+      const action = {
+        type: ActionTypes.ADD_COMPANION_WINDOW,
+        id: 'abc123',
+        payload: { content: 'info', position: 'right' },
+      };
+      const beforeState = {};
+      const expectedState = {
+        abc123: {
+          position: 'right',
+          content: 'info',
+        },
+      };
+      expect(companionWindowsReducer(beforeState, action)).toEqual(expectedState);
+    });
+  });
+
+  describe('UPDATE_COMPANION_WINDOW', () => {
+    it('updates an existing companion window', () => {
+      const action = {
+        type: ActionTypes.UPDATE_COMPANION_WINDOW,
+        id: 'abc123',
+        payload: { content: 'canvases', foo: 'bar' },
+      };
+      const beforeState = {
+        abc123: {
+          position: 'right',
+          content: 'info',
+        },
+      };
+      const expectedState = {
+        abc123: {
+          position: 'right',
+          content: 'canvases',
+          foo: 'bar',
+        },
+      };
+      expect(companionWindowsReducer(beforeState, action)).toEqual(expectedState);
+    });
+  });
+
+  describe('REMOVE_COMPANION_WINDOW', () => {
+    it('should remove a companion window', () => {
+      const action = {
+        type: ActionTypes.REMOVE_COMPANION_WINDOW,
+        id: 'abc123',
+      };
+      const beforeState = {
+        abc123: {
+          position: 'right',
+          content: 'info',
+        },
+      };
+      const expectedState = {};
+      expect(companionWindowsReducer(beforeState, action)).toEqual(expectedState);
+    });
+  });
+});
diff --git a/__tests__/src/reducers/companion_windows.test.js b/__tests__/src/reducers/companion_windows.test.js
deleted file mode 100644
index ab0d0c5f465e357d86de385ad7c7bd2ad1dbff0c..0000000000000000000000000000000000000000
--- a/__tests__/src/reducers/companion_windows.test.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import { companionWindowsReducer } from '../../../src/state/reducers/companion_windows';
-import ActionTypes from '../../../src/state/actions/action-types';
-
-describe('companionWindowsReducer', () => {
-  describe('SET_COMPANION_WINDOW', () => {
-    it('adds a new companion window if a companion window for the given position does not exist', () => {
-      const action = {
-        type: ActionTypes.SET_COMPANION_WINDOW,
-        id: 'abc123',
-        windowId: 'x',
-        position: 'right',
-        content: 'info',
-      };
-      const beforeState = {};
-      const expectedState = {
-        abc123: {
-          id: 'abc123', windowId: 'x', position: 'right', content: 'info',
-        },
-      };
-
-      expect(companionWindowsReducer(beforeState, action)).toEqual(expectedState);
-    });
-
-    it('updates an existing companion window based on windowId and position (regardless of companionWindowId)', () => {
-      const action = {
-        type: ActionTypes.SET_COMPANION_WINDOW,
-        id: 'xyz321',
-        windowId: 'x',
-        position: 'right',
-        content: 'info',
-      };
-      const beforeState = {
-        abc123: {
-          id: 'abc123', windowId: 'x', position: 'right', content: 'canvas_navigation',
-        },
-      };
-      const expectedState = {
-        abc123: {
-          id: 'abc123', windowId: 'x', position: 'right', content: 'info',
-        },
-      };
-
-      expect(companionWindowsReducer(beforeState, action)).toEqual(expectedState);
-    });
-  });
-
-  describe('REMOVE_COMPANION_WINDOW', () => {
-    it('removes the companion window w/ the given ID', () => {
-      const action = { type: ActionTypes.REMOVE_COMPANION_WINDOW, id: 'abc123' };
-      const beforeState = { abc123: { id: 'abc123' } };
-      const expectedState = {};
-
-      expect(companionWindowsReducer(beforeState, action)).toEqual(expectedState);
-    });
-  });
-
-  describe('REMOVE_WINDOW', () => {
-    it('removes any companion window that has the given windowId', () => {
-      const action = {
-        type: ActionTypes.REMOVE_WINDOW,
-        windowId: 'x',
-      };
-      const beforeState = {
-        abc123: { windowId: 'x' },
-        abc456: { windowId: 'y' },
-        abc789: { windowId: 'x' },
-      };
-      const expectedState = {
-        abc456: { windowId: 'y' },
-      };
-
-      expect(companionWindowsReducer(beforeState, action)).toEqual(expectedState);
-    });
-  });
-});
diff --git a/__tests__/src/reducers/windows.test.js b/__tests__/src/reducers/windows.test.js
index 7402360aa7cfdb5a16be3998f4edf9f0fb4fc908..e8beeabbbf756d5feda29645d26af0751986b2a8 100644
--- a/__tests__/src/reducers/windows.test.js
+++ b/__tests__/src/reducers/windows.test.js
@@ -121,61 +121,6 @@ describe('windows reducer', () => {
     });
   });
 
-  describe('SET_COMPANION_WINDOW', () => {
-    it('adds the id to the companin array', () => {
-      const action = {
-        type: ActionTypes.SET_COMPANION_WINDOW,
-        id: 'x',
-        windowId: 'abc123',
-      };
-      const before = {
-        abc123: { companionWindowIds: [] },
-      };
-      const after = {
-        abc123: { companionWindowIds: ['x'] },
-      };
-
-      expect(windowsReducer(before, action)).toEqual(after);
-    });
-
-    it('does not add id key that already exists', () => {
-      const action = {
-        type: ActionTypes.SET_COMPANION_WINDOW,
-        id: 'x',
-        windowId: 'abc123',
-        position: 'right',
-        panelType: 'info',
-      };
-      const before = {
-        abc123: { companionWindowIds: ['x'] },
-      };
-
-      const after = {
-        abc123: { companionWindowIds: ['x'] },
-      };
-
-      expect(windowsReducer(before, action)).toEqual(after);
-    });
-  });
-
-  describe('REMOVE_COMPANION_WINDOW', () => {
-    it('removes the id of the companionWindow from the ids array', () => {
-      const action = {
-        type: ActionTypes.REMOVE_COMPANION_WINDOW,
-        id: 'x',
-        windowId: 'abc123',
-      };
-      const before = {
-        abc123: { companionWindowIds: ['x'] },
-      };
-      const after = {
-        abc123: { companionWindowIds: [] },
-      };
-
-      expect(windowsReducer(before, action)).toEqual(after);
-    });
-  });
-
   it('should handle NEXT_CANVAS', () => {
     expect(windowsReducer({
       abc123: {
@@ -249,4 +194,28 @@ describe('windows reducer', () => {
       },
     });
   });
+
+  describe('UPDATE_WINDOW', () => {
+    it('updates an existing window', () => {
+      const action = {
+        type: ActionTypes.UPDATE_WINDOW,
+        id: 'abc123',
+        payload: { foo: 11, baz: 33 },
+      };
+      const beforeState = {
+        abc123: {
+          foo: 1,
+          bar: 2,
+        },
+      };
+      const expectedState = {
+        abc123: {
+          foo: 11,
+          bar: 2,
+          baz: 33,
+        },
+      };
+      expect(windowsReducer(beforeState, action)).toEqual(expectedState);
+    });
+  });
 });
diff --git a/package.json b/package.json
index 3378f26d956f2ebc84d388b8874de98a545c6ee0..156228a973f2ae817a969b06a9d7f2224c32a88c 100644
--- a/package.json
+++ b/package.json
@@ -36,6 +36,7 @@
     "deepmerge": "^3.1.0",
     "dompurify": "^1.0.9",
     "i18next": "^14.0.1",
+    "immutable": "^4.0.0-rc.12",
     "intersection-observer": "^0.5.1",
     "lodash": "^4.17.11",
     "manifesto.js": "^3.0.9",
diff --git a/src/components/CompanionWindow.js b/src/components/CompanionWindow.js
index 18c104fee0e090fa0fe5f0d2d359e5b0c7f6a582..b26f2f84ce1b900d64c531b9dca218a779650b55 100644
--- a/src/components/CompanionWindow.js
+++ b/src/components/CompanionWindow.js
@@ -48,7 +48,7 @@ class CompanionWindow extends Component {
         <IconButton
           aria-label={t('closeCompanionWindow')}
           className={classes.closeButton}
-          onClick={() => { onCloseClick(id, windowId); }}
+          onClick={() => { onCloseClick(windowId, id); }}
         >
           <CloseIcon />
         </IconButton>
diff --git a/src/components/WindowMiddleContent.js b/src/components/WindowMiddleContent.js
index ce86d5644d5a7851154cdfb8ea8b3a75f7a3fa67..b2817e6b68d508c5898c51b06e0fcde6ea68fc3d 100644
--- a/src/components/WindowMiddleContent.js
+++ b/src/components/WindowMiddleContent.js
@@ -32,29 +32,24 @@ class WindowMiddleContent extends Component {
    * Render the component
    */
   render() {
-    const { rightCompanionWindowId, window } = this.props;
+    const { companionWindowIds, window } = this.props;
     return (
       <div className={ns('window-middle-content')}>
         <WindowSideBar windowId={window.id} />
         {this.renderViewer()}
-        { // We can pass an array of ids here when we want to support
-          // multiple companion windows in a particular position
-          rightCompanionWindowId
-            && <CompanionWindow id={rightCompanionWindowId} windowId={window.id} />
-        }
+        { companionWindowIds.map(id => <CompanionWindow key={id} id={id} windowId={window.id} />) }
       </div>
     );
   }
 }
 
 WindowMiddleContent.propTypes = {
-  rightCompanionWindowId: PropTypes.string,
+  companionWindowIds: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
   window: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
   manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types
 };
 
 WindowMiddleContent.defaultProps = {
-  rightCompanionWindowId: null,
   manifest: null,
 };
 
diff --git a/src/components/WindowTopBar.js b/src/components/WindowTopBar.js
index 7e5969cd85d2d4602eb03e57c90cba13db76d4a8..846fe95780dc0d91dd256a410a856a66bacc5f2c 100644
--- a/src/components/WindowTopBar.js
+++ b/src/components/WindowTopBar.js
@@ -24,7 +24,7 @@ class WindowTopBar extends Component {
    */
   render() {
     const {
-      removeWindow, windowId, classes, toggleWindowSideBar, t, manifestTitle,
+      closeWindow, windowId, classes, toggleWindowSideBar, t, manifestTitle,
     } = this.props;
     return (
       <AppBar position="relative">
@@ -46,7 +46,7 @@ class WindowTopBar extends Component {
             color="inherit"
             className={ns('window-close')}
             aria-label={t('closeWindow')}
-            onClick={removeWindow}
+            onClick={closeWindow}
           >
             <CloseIcon />
           </IconButton>
@@ -58,7 +58,7 @@ class WindowTopBar extends Component {
 
 WindowTopBar.propTypes = {
   manifestTitle: PropTypes.string,
-  removeWindow: PropTypes.func.isRequired,
+  closeWindow: PropTypes.func.isRequired,
   windowId: PropTypes.string.isRequired,
   classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
   toggleWindowSideBar: PropTypes.func.isRequired,
diff --git a/src/containers/CompanionWindow.js b/src/containers/CompanionWindow.js
index c5801ba9ab1b2390206bbe5651eaa967028d8502..0572435bf5a9c4fd7bc012dcdf47cacbc4b96d60 100644
--- a/src/containers/CompanionWindow.js
+++ b/src/containers/CompanionWindow.js
@@ -27,7 +27,7 @@ const mapStateToProps = (state, { id }) => {
  * @private
  */
 const mapDispatchToProps = {
-  onCloseClick: actions.removeCompanionWindow,
+  onCloseClick: actions.closeCompanionWindow,
 };
 
 const enhance = compose(
diff --git a/src/containers/WindowMiddleContent.js b/src/containers/WindowMiddleContent.js
index 81630c71069f99014e6141f58982fb47e81bffa1..9ca434593329cc514e680d4a05b0be79b0fc5860 100644
--- a/src/containers/WindowMiddleContent.js
+++ b/src/containers/WindowMiddleContent.js
@@ -1,17 +1,13 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { getCompanionWindowForPosition } from '../state/selectors';
+import { getCompantionWindowIds } from '../state/selectors';
 import miradorWithPlugins from '../lib/miradorWithPlugins';
 import WindowMiddleContent from '../components/WindowMiddleContent';
 
 /** */
-const mapStateToProps = (state, { window }) => {
-  const rightCompanionWindow = getCompanionWindowForPosition(state, window.id, 'right');
-
-  return {
-    rightCompanionWindowId: rightCompanionWindow && rightCompanionWindow.id,
-  };
-};
+const mapStateToProps = (state, { window }) => ({
+  companionWindowIds: getCompantionWindowIds(state, window.id),
+});
 
 const enhance = compose(
   connect(mapStateToProps, null),
diff --git a/src/containers/WindowTopBar.js b/src/containers/WindowTopBar.js
index 1d193b101f5f425ea21d5de7a37248d3509ab0b4..191ebb59ca3256d1f782028fc4f3583a9c30f3fb 100644
--- a/src/containers/WindowTopBar.js
+++ b/src/containers/WindowTopBar.js
@@ -17,7 +17,7 @@ const mapStateToProps = (state, { windowId }) => ({
  * @private
  */
 const mapDispatchToProps = (dispatch, { windowId }) => ({
-  removeWindow: () => dispatch(actions.removeWindow(windowId)),
+  closeWindow: () => dispatch(actions.closeWindow(windowId)),
   toggleWindowSideBar: () => dispatch(actions.toggleWindowSideBar(windowId)),
 });
 
diff --git a/src/state/actions/action-types.js b/src/state/actions/action-types.js
index 79c13ef4168f36a45c33575e159887885ce680c1..117eda9052691186eea6ead2d20257607cc8c702 100644
--- a/src/state/actions/action-types.js
+++ b/src/state/actions/action-types.js
@@ -1,6 +1,9 @@
 const ActionTypes = {
-  SET_COMPANION_WINDOW: 'SET_COMPANION_WINDOW',
+  ADD_COMPANION_WINDOW: 'ADD_COMPANION_WINDOW',
+  UPDATE_COMPANION_WINDOW: 'UPDATE_COMPANION_WINDOW',
   REMOVE_COMPANION_WINDOW: 'REMOVE_COMPANION_WINDOW',
+  UPDATE_WINDOW: 'UPDATE_WINDOW',
+
   FOCUS_WINDOW: 'FOCUS_WINDOW',
   SET_WORKSPACE_FULLSCREEN: 'SET_WORKSPACE_FULLSCREEN',
   ADD_MANIFEST: 'ADD_MANIFEST',
diff --git a/src/state/actions/companionWindow.js b/src/state/actions/companionWindow.js
index d86ed66d8a72890e644720a779d79fa0381d8010..43b27cab8db26afe77da928cf4f6b659c32cf2eb 100644
--- a/src/state/actions/companionWindow.js
+++ b/src/state/actions/companionWindow.js
@@ -1,30 +1,26 @@
 import uuid from 'uuid/v4';
 import ActionTypes from './action-types';
 
-/**
- * addCompanionWindow - action creator
- *
- * @param  {Object} options
- * @memberof ActionCreators
- */
-export function addCompanionWindow(companionWindow) {
+const defaultProps = {
+  content: null,
+  position: null,
+};
+
+/** */
+export function addCompanionWindow(payload, defaults = defaultProps) {
   return {
-    type: ActionTypes.SET_COMPANION_WINDOW,
+    type: ActionTypes.ADD_COMPANION_WINDOW,
     id: `cw-${uuid()}`,
-    ...companionWindow,
+    payload: { ...defaults, ...payload },
   };
 }
 
-/**
- * removeCompanionWindow - action creator
- *
- * @param  {Object} options
- * @memberof ActionCreators
- */
-export function removeCompanionWindow(id, windowId) {
-  return {
-    type: ActionTypes.REMOVE_COMPANION_WINDOW,
-    id,
-    windowId,
-  };
+/** */
+export function updateCompanionWindow(id, payload) {
+  return { type: ActionTypes.UPDATE_COMPANION_WINDOW, id, payload };
+}
+
+/** */
+export function removeCompanionWindow(id) {
+  return { type: ActionTypes.REMOVE_COMPANION_WINDOW, id };
 }
diff --git a/src/state/actions/window.js b/src/state/actions/window.js
index 86d35bbdabed47d3e92f32129934e0ea039d0d4c..afb5c766f61eaea98e0ec3b6c4edca3861826e80 100644
--- a/src/state/actions/window.js
+++ b/src/state/actions/window.js
@@ -1,6 +1,6 @@
 import uuid from 'uuid/v4';
 import ActionTypes from './action-types';
-import { addCompanionWindow } from './companionWindow';
+import { addCompanionWindow, removeCompanionWindow } from './companionWindow';
 
 /**
  * focusWindow - action creator
@@ -34,6 +34,11 @@ export function addWindow(options) {
   return { type: ActionTypes.ADD_WINDOW, window: { ...defaultOptions, ...options } };
 }
 
+/** */
+export function updateWindow(id, payload) {
+  return { type: ActionTypes.UPDATE_WINDOW, id, payload };
+}
+
 /**
  * removeWindow - action creator
  *
@@ -76,10 +81,40 @@ export function toggleWindowSideBarPanel(windowId, panelType) {
  * @memberof ActionCreators
  */
 export function popOutCompanionWindow(windowId, panelType, position) {
-  return ((dispatch) => {
-    dispatch(addCompanionWindow({ windowId, content: panelType, position }));
+  return (dispatch, getState) => {
+    const { companionWindowIds } = getState().windows[windowId];
+    companionWindowIds.map(id => dispatch(removeCompanionWindow(id)));
+
+    const action = dispatch(addCompanionWindow({ content: panelType, position }));
+
+    const companionWindowId = action.id;
+    dispatch(updateWindow(windowId, { companionWindowIds: [companionWindowId] }));
+
     dispatch(toggleWindowSideBarPanel(windowId, 'closed'));
-  });
+  };
+}
+
+/**
+* Clean up state and remove window
+*/
+export function closeWindow(windowId) {
+  return (dispatch, getState) => {
+    const { companionWindowIds } = getState().windows[windowId];
+    companionWindowIds.map(id => dispatch(removeCompanionWindow(id)));
+    dispatch(removeWindow(windowId));
+  };
+}
+
+/**
+* Close companion window and remove reference from window
+*/
+export function closeCompanionWindow(windowId, companionWindowId) {
+  return (dispatch, getState) => {
+    dispatch(removeCompanionWindow(companionWindowId));
+    const companionWindowIds = getState().windows[windowId].companionWindowIds
+      .filter(id => id !== companionWindowId);
+    dispatch(updateWindow(windowId, { companionWindowIds }));
+  };
 }
 
 /**
diff --git a/src/state/reducers/companionWindows.js b/src/state/reducers/companionWindows.js
new file mode 100644
index 0000000000000000000000000000000000000000..c5cfc2dcc685b5570d1563974c423124591fcaf9
--- /dev/null
+++ b/src/state/reducers/companionWindows.js
@@ -0,0 +1,21 @@
+import {
+  removeIn, setIn, updateIn, merge,
+} from 'immutable';
+import ActionTypes from '../actions/action-types';
+
+/** */
+export function companionWindowsReducer(state = {}, action) {
+  switch (action.type) {
+    case ActionTypes.ADD_COMPANION_WINDOW:
+      return setIn(state, [action.id], action.payload);
+
+    case ActionTypes.UPDATE_COMPANION_WINDOW:
+      return updateIn(state, [action.id], orig => merge(orig, action.payload));
+
+    case ActionTypes.REMOVE_COMPANION_WINDOW:
+      return removeIn(state, [action.id]);
+
+    default:
+      return state;
+  }
+}
diff --git a/src/state/reducers/companion_windows.js b/src/state/reducers/companion_windows.js
deleted file mode 100644
index d703a2352c2665325cc8248bd9ba3d8d68ae3cb5..0000000000000000000000000000000000000000
--- a/src/state/reducers/companion_windows.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import ActionTypes from '../actions/action-types';
-import { getCompanionWindowForPosition } from '../selectors';
-
-/**
- * companionWindowsReducer
- */
-export const companionWindowsReducer = (state = {}, action) => {
-  switch (action.type) {
-    // action params: id
-    case ActionTypes.REMOVE_COMPANION_WINDOW:
-      return Object.keys(state).reduce((object, key) => {
-        if (state[key].id !== action.id) {
-          object[key] = state[key]; // eslint-disable-line no-param-reassign
-        }
-        return object;
-      }, {});
-    // action params: id, windowId, position, content
-    case ActionTypes.SET_COMPANION_WINDOW: {
-      const companionWindowForPosition = getCompanionWindowForPosition(
-        { companionWindows: state }, action.windowId, action.position,
-      );
-      let cwId;
-      let cwObject;
-
-      if (companionWindowForPosition) {
-        cwId = companionWindowForPosition.id;
-        cwObject = {
-          ...companionWindowForPosition,
-          position: action.position,
-          content: action.content,
-        };
-      } else {
-        cwId = action.id;
-        cwObject = {
-          id: cwId, windowId: action.windowId, position: action.position, content: action.content,
-        };
-      }
-
-      return { ...state, [cwId]: cwObject };
-    }
-
-
-    // action params: windowId
-    case ActionTypes.REMOVE_WINDOW:
-      return Object.keys(state).reduce((object, key) => {
-        if (state[key].windowId !== action.windowId) {
-          object[key] = state[key]; // eslint-disable-line no-param-reassign
-        }
-        return object;
-      }, {});
-    default:
-      return state;
-  }
-};
diff --git a/src/state/reducers/index.js b/src/state/reducers/index.js
index 626131733a5407542f206249d2d963946dab76fc..478ac4467e511e258bce3edd51967b9d7496cc10 100644
--- a/src/state/reducers/index.js
+++ b/src/state/reducers/index.js
@@ -1,4 +1,4 @@
-export * from './companion_windows';
+export * from './companionWindows';
 export * from './workspace';
 export * from './windows';
 export * from './manifests';
diff --git a/src/state/reducers/windows.js b/src/state/reducers/windows.js
index 5530e897ee3ee41bc3f53718d1f92a0c597f8843..7a1739f8e481d9380bd89d709ea843be247a481c 100644
--- a/src/state/reducers/windows.js
+++ b/src/state/reducers/windows.js
@@ -1,3 +1,4 @@
+import { updateIn, merge } from 'immutable';
 import ActionTypes from '../actions/action-types';
 
 /**
@@ -7,6 +8,10 @@ export const windowsReducer = (state = {}, action) => {
   switch (action.type) {
     case ActionTypes.ADD_WINDOW:
       return { ...state, [action.window.id]: action.window };
+
+    case ActionTypes.UPDATE_WINDOW:
+      return updateIn(state, [action.id], orig => merge(orig, action.payload));
+
     case ActionTypes.REMOVE_WINDOW:
       return Object.keys(state).reduce((object, key) => {
         if (key !== action.windowId) {
@@ -50,26 +55,6 @@ export const windowsReducer = (state = {}, action) => {
           ),
         },
       };
-    case ActionTypes.SET_COMPANION_WINDOW: {
-      return {
-        ...state,
-        [action.windowId]: {
-          ...state[action.windowId],
-          companionWindowIds: Array.from(
-            new Set([].concat(state[action.windowId].companionWindowIds, action.id)),
-          ),
-        },
-      };
-    }
-    case ActionTypes.REMOVE_COMPANION_WINDOW:
-      return {
-        ...state,
-        [action.windowId]: {
-          ...state[action.windowId],
-          companionWindowIds: state[action.windowId]
-            .companionWindowIds.filter(id => id !== action.id),
-        },
-      };
     case ActionTypes.NEXT_CANVAS:
       return setCanvasIndex(state, action.windowId, currentIndex => currentIndex + 1);
     case ActionTypes.PREVIOUS_CANVAS:
diff --git a/src/state/selectors/index.js b/src/state/selectors/index.js
index 1b3333583b782fe1628a6dc267e19c19f463eca6..e7b4565c634581f94ddc3ff0caf2e9f251c2dacd 100644
--- a/src/state/selectors/index.js
+++ b/src/state/selectors/index.js
@@ -192,3 +192,12 @@ export function getCompanionWindowForPosition(state, windowId, position) {
     cw.windowId === windowId && cw.position === position
   ));
 }
+
+/**
+* Return compantion window ids from a window
+* @param {String} windowId
+* @return {Array}
+*/
+export function getCompantionWindowIds(state, windowId) {
+  return state.windows[windowId].companionWindowIds;
+}