diff --git a/__tests__/integration/mirador/window_sidebar.test.js b/__tests__/integration/mirador/window_sidebar.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..9a8ad697bfb99804f483448ad09d1c6b54a88172
--- /dev/null
+++ b/__tests__/integration/mirador/window_sidebar.test.js
@@ -0,0 +1,35 @@
+/* global miradorInstance */
+
+describe('Window Sidebars', () => {
+  beforeAll(async () => {
+    await page.goto('http://127.0.0.1:4488/__tests__/integration/mirador/');
+  });
+
+  it('renders and updates canvas level metadata', async () => {
+    await expect(page).toClick('#addBtn');
+    await expect(page).toFill('#manifestURL', 'http://localhost:5000/api/001');
+    await expect(page).toClick('#fetchBtn');
+    // TODO: Refactor the app so we get rid of the wait
+    await page.waitFor(1000);
+    await expect(page).toMatchElement('li', { text: 'http://localhost:5000/api/001' });
+    await expect(page).toClick('li button', { text: 'http://localhost:5000/api/001' });
+
+    await expect(page).toMatchElement(
+      'h3',
+      { text: 'Bodleian Library Human Freaks 2 (33)' },
+    );
+
+    const windows = await page.evaluate(() => (
+      miradorInstance.store.getState().windows
+    ));
+
+    const windowId = Object.values(windows)
+      .find(window => window.manifestId === 'http://localhost:5000/api/001')
+      .id;
+
+    await expect(page).toMatchElement(`#${windowId} button[aria-label="Toggle window sidebar"]`);
+    await expect(page).toClick(`#${windowId} button[aria-label="Toggle window sidebar"]`);
+
+    await expect(page).toMatchElement(`#${windowId} button[aria-label="Open information companion window"]`);
+  });
+});
diff --git a/__tests__/src/components/LabelValueMetadata.test.js b/__tests__/src/components/LabelValueMetadata.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..7eaa41c70b6a15aed121cf5b549fffcf0594718d
--- /dev/null
+++ b/__tests__/src/components/LabelValueMetadata.test.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import LabelValueMetadata from '../../../src/components/LabelValueMetadata';
+
+describe('LabelValueMetadata', () => {
+  let wrapper;
+  let labelValuePair;
+
+  describe('when the labelValuePair has content', () => {
+    beforeEach(() => {
+      labelValuePair = [
+        {
+          label: 'Label 1',
+          value: 'Value 1',
+        },
+        {
+          label: 'Label 2',
+          value: 'Value 2',
+        },
+      ];
+      wrapper = shallow(
+        <LabelValueMetadata labelValuePairs={labelValuePair} />,
+      );
+    });
+
+    it('renders a dt/dd for each label/value pair', () => {
+      expect(wrapper.find('dl').length).toEqual(1);
+
+      expect(wrapper.find('dt').length).toEqual(2);
+      expect(wrapper.find('dt').first().text()).toEqual('Label 1');
+      expect(wrapper.find('dt').last().text()).toEqual('Label 2');
+
+      expect(wrapper.find('dd').length).toEqual(2);
+      expect(wrapper.find('dd').first().text()).toEqual('Value 1');
+      expect(wrapper.find('dd').last().text()).toEqual('Value 2');
+    });
+  });
+
+  describe('when the labelValuePair has no content', () => {
+    beforeEach(() => {
+      labelValuePair = [];
+      wrapper = shallow(
+        <LabelValueMetadata labelValuePairs={labelValuePair} />,
+      );
+    });
+
+    it('renders an empty fragment instead of an empty dl', () => {
+      expect(wrapper.find('dl').length).toEqual(0);
+      expect(wrapper.matchesElement(<></>)).toBe(true);
+    });
+  });
+});
diff --git a/__tests__/src/components/WindowSideBarInfoPanel.test.js b/__tests__/src/components/WindowSideBarInfoPanel.test.js
index 21c6fabc32f12d3076bea7c6d4862de33376c7fa..ea9d1f7a2214d86e42c75237d0733643bf235deb 100644
--- a/__tests__/src/components/WindowSideBarInfoPanel.test.js
+++ b/__tests__/src/components/WindowSideBarInfoPanel.test.js
@@ -1,41 +1,74 @@
 import React from 'react';
 import { shallow } from 'enzyme';
 import Typography from '@material-ui/core/Typography';
-import createStore from '../../../src/state/createStore';
-import * as actions from '../../../src/state/actions';
 import WindowSideBarInfoPanel from '../../../src/components/WindowSideBarInfoPanel';
-import fixture from '../../fixtures/version-2/001.json';
+import LabelValueMetadata from '../../../src/components/LabelValueMetadata';
 
 describe('WindowSideBarInfoPanel', () => {
   let wrapper;
-  let manifest;
-  const store = createStore();
-
-  beforeEach(() => {
-    store.dispatch(actions.receiveManifest('foo', fixture));
-    manifest = store.getState().manifests.foo;
-    wrapper = shallow(
-      <WindowSideBarInfoPanel manifest={manifest} />,
-    ).dive();
+
+  describe('when metadata is present', () => {
+    beforeEach(() => {
+      wrapper = shallow(
+        <WindowSideBarInfoPanel
+          canvasLabel="The Canvas Label"
+          canvasDescription="The Canvas Description"
+          canvasMetadata={[{ label: {}, value: {} }]}
+          manifestLabel="The Manifest Label"
+          manifestDescription="The Manifest Description"
+        />,
+      ).dive();
+    });
+
+    it('renders canvas level label, description, and metadata', () => {
+      expect(
+        wrapper.find('WithStyles(Typography)[variant="h3"]').first().matchesElement(
+          <Typography>The Canvas Label</Typography>,
+        ),
+      ).toBe(true);
+
+      expect(
+        wrapper.find('WithStyles(Typography)[variant="body2"]').first().matchesElement(
+          <Typography>The Canvas Description</Typography>,
+        ),
+      ).toBe(true);
+
+      expect(wrapper.find(LabelValueMetadata).length).toBe(2); // one for canvas one for manifest
+    });
+
+    it('renders manifest level label, description, and metadata', () => {
+      expect(
+        wrapper.find('WithStyles(Typography)[variant="h3"]').last().matchesElement(
+          <Typography>The Manifest Label</Typography>,
+        ),
+      ).toBe(true);
+
+      expect(
+        wrapper.find('WithStyles(Typography)[variant="body2"]').last().matchesElement(
+          <Typography>The Manifest Description</Typography>,
+        ),
+      ).toBe(true);
+
+      expect(wrapper.find(LabelValueMetadata).length).toBe(2); // one for canvas one for manifest
+    });
   });
 
-  it('renders without an error', () => {
-    expect(
-      wrapper.find('WithStyles(Typography)[variant="h2"]').first().matchesElement(
-        <Typography>aboutThisItem</Typography>,
-      ),
-    ).toBe(true);
-
-    expect(
-      wrapper.find('WithStyles(Typography)[variant="h3"]').first().matchesElement(
-        <Typography>Bodleian Library Human Freaks 2 (33)</Typography>,
-      ),
-    ).toBe(true);
-
-    expect(
-      wrapper.find('WithStyles(Typography)[variant="body2"]').first().matchesElement(
-        <Typography>[Handbill of Mr. Becket, [1787] ]</Typography>,
-      ),
-    ).toBe(true);
+  describe('when metadata is not present', () => {
+    beforeEach(() => {
+      wrapper = shallow(
+        <WindowSideBarInfoPanel />,
+      ).dive();
+    });
+
+    it('does not render empty elements', () => {
+      expect(
+        wrapper.find('WithStyles(Typography)[variant="h2"]').first().matchesElement(
+          <Typography>aboutThisItem</Typography>,
+        ),
+      ).toBe(true);
+
+      expect(wrapper.find('WithStyles(Typography)[variant="h3"]').length).toEqual(0);
+      expect(wrapper.find('WithStyles(Typography)[variant="body2"]').length).toEqual(0);
+    });
   });
 });
diff --git a/__tests__/src/components/WindowSideBarPanel.test.js b/__tests__/src/components/WindowSideBarPanel.test.js
index f31c05019910c90a36cb66ede06d229e6d24a5f7..49caad0e50aa4c874fcd7f8e215d315307895615 100644
--- a/__tests__/src/components/WindowSideBarPanel.test.js
+++ b/__tests__/src/components/WindowSideBarPanel.test.js
@@ -1,24 +1,14 @@
 import React from 'react';
 import { shallow } from 'enzyme';
-import createStore from '../../../src/state/createStore';
-import * as actions from '../../../src/state/actions';
 import WindowSideBarPanel from '../../../src/components/WindowSideBarPanel';
 import WindowSideBarInfoPanel from '../../../src/containers/WindowSideBarInfoPanel';
-import fixture from '../../fixtures/version-2/001.json';
 
 describe('WindowSideBarPanel', () => {
   let wrapper;
-  let manifest;
-  const store = createStore();
-
-  beforeEach(() => {
-    store.dispatch(actions.receiveManifest('foo', fixture));
-    manifest = store.getState().manifests.foo;
-  });
 
   describe('when the sideBarPanel is set to "info"', () => {
     beforeEach(() => {
-      wrapper = shallow(<WindowSideBarPanel sideBarPanel="info" manifest={manifest} />);
+      wrapper = shallow(<WindowSideBarPanel windowId="abc123" sideBarPanel="info" />);
     });
 
     it('renders the WindowSideBarInfoPanel', () => {
@@ -28,7 +18,7 @@ describe('WindowSideBarPanel', () => {
 
   describe('when the sideBarPanel is set to "closed" (or any other unknown value)', () => {
     beforeEach(() => {
-      wrapper = shallow(<WindowSideBarPanel sideBarPanel="closed" manifest={manifest} />);
+      wrapper = shallow(<WindowSideBarPanel windowId="abc123" sideBarPanel="closed" />);
     });
 
     it('does not render any panel component', () => {
diff --git a/__tests__/src/selectors/index.test.js b/__tests__/src/selectors/index.test.js
index 1e7b7a0566550ad919d686b111a01c40dfc5e21b..63e42b16fd99f84a7b2b9883406bf5427e41d422 100644
--- a/__tests__/src/selectors/index.test.js
+++ b/__tests__/src/selectors/index.test.js
@@ -1,9 +1,15 @@
 import manifesto from 'manifesto.js';
 import manifestFixture001 from '../../fixtures/version-2/001.json';
+import manifestFixture002 from '../../fixtures/version-2/002.json';
+import manifestFixture019 from '../../fixtures/version-2/019.json';
 import {
+  getCanvasLabel,
+  getDestructuredMetadata,
+  getSelectedCanvas,
   getWindowManifest,
   getManifestLogo,
   getManifestCanvases,
+  getManifestDescription,
   getThumbnailNavigationPosition,
   getManifestTitle,
   getWindowViewType,
@@ -139,3 +145,112 @@ describe('getWindowViewType', () => {
     expect(received).toBeUndefined();
   });
 });
+
+describe('getManifestDescription', () => {
+  it('should return manifest description', () => {
+    const manifest = { manifestation: manifesto.create(manifestFixture001) };
+    const received = getManifestDescription(manifest);
+    expect(received).toBe('[Handbill of Mr. Becket, [1787] ]');
+  });
+
+  it('should return undefined if manifest undefined', () => {
+    const received = getManifestDescription(undefined);
+    expect(received).toBeUndefined();
+  });
+
+  it('should return undefined if no manifestation', () => {
+    const manifest = {};
+    const received = getManifestDescription(manifest);
+    expect(received).toBeUndefined();
+  });
+});
+
+describe('getSelectedCanvas', () => {
+  const state = {
+    windows: {
+      a: {
+        id: 'a',
+        manifestId: 'x',
+        canvasIndex: 1,
+      },
+    },
+    manifests: {
+      x: {
+        id: 'x',
+        manifestation: manifesto.create(manifestFixture019),
+      },
+    },
+  };
+
+  const noManifestationState = {
+    windows: {
+      a: {
+        id: 'a',
+        manifestId: 'x',
+        canvasIndex: 1,
+      },
+    },
+    manifests: {
+      x: {
+        id: 'x',
+      },
+    },
+  };
+
+  it('should return canvas based on the canvas index stored window state', () => {
+    const selectedCanvas = getSelectedCanvas(state, 'a');
+
+    expect(selectedCanvas.id).toEqual(
+      'https://purl.stanford.edu/fr426cg9537/iiif/canvas/fr426cg9537_1',
+    );
+  });
+
+  it('should return an empty object when there is no manifestation to get a canvas from', () => {
+    const selectedCanvas = getSelectedCanvas(noManifestationState, 'a');
+
+    expect(selectedCanvas).toEqual({});
+  });
+});
+
+describe('getCanvasLabel', () => {
+  it('should return label of the canvas', () => {
+    const canvas = manifesto
+      .create(manifestFixture001)
+      .getSequences()[0]
+      .getCanvases()[0];
+
+    const received = getCanvasLabel(canvas);
+    expect(received).toBe('Whole Page');
+  });
+
+  it('should return the given canvas index (+1) if the canvas is undefined', () => {
+    expect(getCanvasLabel(undefined)).toBe(1);
+    expect(getCanvasLabel(undefined, 2)).toBe(3);
+  });
+
+  it('should return the canvas index (+1) if no manifestation', () => {
+    const canvas = { getLabel: () => {} };
+    const received = getCanvasLabel(canvas);
+    expect(received).toBe(1);
+  });
+});
+
+describe('getDestructuredMetadata', () => {
+  it('should return the first value of label/value attributes for each object in the array ', () => {
+    const iiifResource = manifesto.create(manifestFixture002);
+    const received = getDestructuredMetadata(iiifResource);
+    const expected = [{
+      label: 'date',
+      value: 'some date',
+    }];
+
+    expect(received).toEqual(expected);
+  });
+
+  it('returns an empty array if there is no metadata', () => {
+    const iiifResource = manifesto.create(manifestFixture019);
+    const received = getDestructuredMetadata(iiifResource);
+
+    expect(received).toEqual([]);
+  });
+});
diff --git a/src/components/LabelValueMetadata.js b/src/components/LabelValueMetadata.js
new file mode 100644
index 0000000000000000000000000000000000000000..4721dc32d56290d0e7ae9bec12fd16e2f5cc137f
--- /dev/null
+++ b/src/components/LabelValueMetadata.js
@@ -0,0 +1,40 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+
+/**
+ * Renders label/value pair metadata in a dl
+ * @prop {object} labelValuePair
+ */
+class LabelValueMetadata extends Component {
+  /**
+   * render
+   * @return {String} - HTML markup for the component
+   */
+  render() {
+    const { labelValuePairs } = this.props;
+
+    if (labelValuePairs.length === 0) {
+      return (<></>);
+    }
+
+    /* eslint-disable react/no-array-index-key */
+    // Disabling array index key for dt/dd elements as
+    // they are intended to display metadata that will not
+    // need to be re-rendered internally in any meaningful way
+    return (
+      <dl>
+        {labelValuePairs.reduce((acc, labelValuePair, i) => acc.concat([
+          <dt key={`label-${i}`}>{labelValuePair.label}</dt>,
+          <dd key={`value-${i}`}>{labelValuePair.value}</dd>,
+        ]), [])}
+      </dl>
+    );
+    /* eslint-enable react/no-array-index-key */
+  }
+}
+
+LabelValueMetadata.propTypes = {
+  labelValuePairs: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types,
+};
+
+export default LabelValueMetadata;
diff --git a/src/components/Window.js b/src/components/Window.js
index 2d1fec5604b0aa076fd570c83bd5777eb63d7f24..380c1c8383a26237e7f19ec7be96dbcbb56dd500 100644
--- a/src/components/Window.js
+++ b/src/components/Window.js
@@ -16,7 +16,7 @@ class Window extends Component {
   render() {
     const { manifest, window } = this.props;
     return (
-      <div className={ns('window')}>
+      <div id={window.id} className={ns('window')}>
         <WindowTopBar
           windowId={window.id}
           manifest={manifest}
diff --git a/src/components/WindowMiddleContent.js b/src/components/WindowMiddleContent.js
index 766547a3528a327168961ab22a4606fdd2360d6a..c1dd1cca2536de1d3dd00b67e997da9e4f13e3ae 100644
--- a/src/components/WindowMiddleContent.js
+++ b/src/components/WindowMiddleContent.js
@@ -35,12 +35,7 @@ class WindowMiddleContent extends Component {
     const { manifest, window } = this.props;
     return (
       <div className={ns('window-middle-content')}>
-        <WindowSideBar
-          windowId={window.id}
-          manifest={manifest}
-          sideBarOpen={window.sideBarOpen}
-          sideBarPanel={window.sideBarPanel}
-        />
+        <WindowSideBar windowId={window.id} />
         <CompanionWindow
           windowId={window.id}
           manifest={manifest}
diff --git a/src/components/WindowSideBar.js b/src/components/WindowSideBar.js
index 4221c0fcbda3c75a850e73c1c27a1a8ad5955bbe..31d4b7200d0adef39574b0d210bd80114dd4c887 100644
--- a/src/components/WindowSideBar.js
+++ b/src/components/WindowSideBar.js
@@ -5,7 +5,7 @@ import Drawer from '@material-ui/core/Drawer';
 import { withStyles } from '@material-ui/core/styles';
 import List from '@material-ui/core/List';
 import WindowSideBarButtons from '../containers/WindowSideBarButtons';
-import WindowSideBarPanel from './WindowSideBarPanel';
+import WindowSideBarPanel from '../containers/WindowSideBarPanel';
 import ns from '../config/css-ns';
 
 /**
@@ -18,7 +18,7 @@ class WindowSideBar extends Component {
    */
   render() {
     const {
-      classes, manifest, windowId, sideBarOpen, sideBarPanel,
+      classes, windowId, sideBarOpen, sideBarPanel,
     } = this.props;
 
     return (
@@ -38,7 +38,7 @@ class WindowSideBar extends Component {
           }}
         >
           <List>
-            <WindowSideBarButtons windowId={windowId} sideBarPanel={sideBarPanel} />
+            <WindowSideBarButtons windowId={windowId} />
           </List>
         </Drawer>
         <Drawer
@@ -55,11 +55,7 @@ class WindowSideBar extends Component {
             style: { position: 'absolute', width: '200px' },
           }}
         >
-          <WindowSideBarPanel
-            manifest={manifest}
-            windowId={windowId}
-            sideBarPanel={sideBarPanel}
-          />
+          <WindowSideBarPanel windowId={windowId} />
         </Drawer>
       </>
     );
@@ -69,14 +65,12 @@ class WindowSideBar extends Component {
 
 WindowSideBar.propTypes = {
   classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types,
-  manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   windowId: PropTypes.string.isRequired,
   sideBarOpen: PropTypes.bool,
   sideBarPanel: PropTypes.string,
 };
 
 WindowSideBar.defaultProps = {
-  manifest: {},
   sideBarOpen: false,
   sideBarPanel: 'closed',
 };
diff --git a/src/components/WindowSideBarInfoPanel.js b/src/components/WindowSideBarInfoPanel.js
index aa646786848c2b78dd24c9efa59b7790c86a93d9..9766310542c71b49fbf390bb8fd7816a8b9e78f4 100644
--- a/src/components/WindowSideBarInfoPanel.js
+++ b/src/components/WindowSideBarInfoPanel.js
@@ -1,65 +1,65 @@
 import React, { Component } from 'react';
 import PropTypes from 'prop-types';
+import Divider from '@material-ui/core/Divider';
 import Typography from '@material-ui/core/Typography';
 import { withStyles } from '@material-ui/core/styles';
+import LabelValueMetadata from './LabelValueMetadata';
 import ns from '../config/css-ns';
 
 /**
  * WindowSideBarInfoPanel
  */
 class WindowSideBarInfoPanel extends Component {
-  /**
-   * manifestLabel - get the label from the manifesto manifestation
-   * @return String
-   */
-  manifestLabel() {
-    const { manifest } = this.props;
-
-    if (manifest.manifestation) {
-      return manifest.manifestation.getLabel().map(label => label.value)[0];
-    }
-    return '';
-  }
-
-  /**
-   * manifestDescription - get the description from the manifesto manifestation
-   * @return String
-   */
-  manifestDescription() {
-    const { manifest } = this.props;
-
-    if (manifest.manifestation) {
-      return manifest.manifestation.getDescription().map(label => label.value);
-    }
-    return '';
-  }
-
   /**
    * render
    * @return
    */
   render() {
-    const { classes, t } = this.props;
+    const {
+      canvasDescription,
+      canvasLabel,
+      canvasMetadata,
+      classes,
+      manifestDescription,
+      manifestLabel,
+      manifestMetadata,
+      t,
+    } = this.props;
     return (
       <div className={ns('window-sidebar-info-panel')}>
         <Typography variant="h2" className={classes.windowSideBarH2}>{t('aboutThisItem')}</Typography>
-        <Typography variant="h3" className={classes.windowSideBarH3}>{this.manifestLabel()}</Typography>
-        <Typography variant="body2">{this.manifestDescription()}</Typography>
+        {canvasLabel && <Typography variant="h3" className={classes.windowSideBarH3}>{canvasLabel}</Typography>}
+        {canvasDescription && <Typography variant="body2">{canvasDescription}</Typography>}
+        {canvasMetadata && <LabelValueMetadata labelValuePairs={canvasMetadata} />}
+        <Divider />
+        {manifestLabel && <Typography variant="h3" className={classes.windowSideBarH3}>{manifestLabel}</Typography>}
+        {manifestDescription && <Typography variant="body2">{manifestDescription}</Typography>}
+        {manifestMetadata && <LabelValueMetadata labelValuePairs={manifestMetadata} />}
       </div>
     );
   }
 }
 
 WindowSideBarInfoPanel.propTypes = {
+  canvasDescription: PropTypes.string,
+  canvasLabel: PropTypes.string,
+  canvasMetadata: PropTypes.array, // eslint-disable-line react/forbid-prop-types
   classes: PropTypes.object, // eslint-disable-line react/forbid-prop-types
-  manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types
+  manifestLabel: PropTypes.string,
+  manifestDescription: PropTypes.string,
+  manifestMetadata: PropTypes.array, // eslint-disable-line react/forbid-prop-types
   t: PropTypes.func,
 };
 
 
 WindowSideBarInfoPanel.defaultProps = {
+  canvasDescription: null,
+  canvasLabel: null,
+  canvasMetadata: [],
   classes: {},
-  manifest: {},
+  manifestLabel: null,
+  manifestDescription: null,
+  manifestMetadata: [],
   t: key => key,
 };
 
diff --git a/src/components/WindowSideBarPanel.js b/src/components/WindowSideBarPanel.js
index 2d647b70178e3c29f8e028f6d16f5f0dd77c1f2f..a0dd1bfeca168b1f2c7252737707518a3567125d 100644
--- a/src/components/WindowSideBarPanel.js
+++ b/src/components/WindowSideBarPanel.js
@@ -12,10 +12,10 @@ class WindowSideBarPanel extends Component {
    * @return React Component
    */
   activePanelComponent() {
-    const { manifest, sideBarPanel } = this.props;
+    const { windowId, sideBarPanel } = this.props;
     switch (sideBarPanel) {
       case 'info':
-        return <WindowSideBarInfoPanel manifest={manifest} />;
+        return <WindowSideBarInfoPanel windowId={windowId} />;
       default:
         return null;
     }
@@ -35,11 +35,10 @@ class WindowSideBarPanel extends Component {
 }
 
 WindowSideBarPanel.propTypes = {
-  manifest: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   sideBarPanel: PropTypes.string,
+  windowId: PropTypes.string.isRequired,
 };
 WindowSideBarPanel.defaultProps = {
-  manifest: {},
   sideBarPanel: 'closed', // Closed will fall out to the default null case for the actiuve panel
 };
 
diff --git a/src/containers/WindowSideBar.js b/src/containers/WindowSideBar.js
index fbdc2c2f599ea654bde3c7a0410f5ef86ed9a4a3..0a7232205cf9b63c7f35e1baca9a067e1d12d210 100644
--- a/src/containers/WindowSideBar.js
+++ b/src/containers/WindowSideBar.js
@@ -1,4 +1,24 @@
+import { connect } from 'react-redux';
+import { compose } from 'redux';
 import miradorWithPlugins from '../lib/miradorWithPlugins';
 import WindowSideBar from '../components/WindowSideBar';
 
-export default miradorWithPlugins(WindowSideBar);
+/**
+ * mapStateToProps - to hook up connect
+ * @memberof WindowSideBar
+ * @private
+ */
+const mapStateToProps = (state, props) => (
+  {
+    sideBarOpen: state.windows[props.windowId].sideBarOpen,
+    sideBarPanel: state.windows[props.windowId].sideBarPanel,
+  }
+);
+
+const enhance = compose(
+  connect(mapStateToProps, null),
+  miradorWithPlugins,
+  // further HOC
+);
+
+export default enhance(WindowSideBar);
diff --git a/src/containers/WindowSideBarButtons.js b/src/containers/WindowSideBarButtons.js
index e4a652b3483c0e250c4d81a0f7fb49d13bf650aa..b95a16ffd930441dff96d2d0844efaee542a0b9d 100644
--- a/src/containers/WindowSideBarButtons.js
+++ b/src/containers/WindowSideBarButtons.js
@@ -17,8 +17,19 @@ const mapDispatchToProps = (dispatch, props) => ({
   ),
 });
 
+
+/**
+ * mapStateToProps - used to hook up connect to state
+ * @memberof WindowSideButtons
+ * @private
+ */
+const mapStateToProps = (state, { windowId }) => ({
+  sideBarPanel: state.windows[windowId].sideBarPanel,
+});
+
+
 const enhance = compose(
-  connect(null, mapDispatchToProps),
+  connect(mapStateToProps, mapDispatchToProps),
   miradorWithPlugins,
   withNamespaces(),
   // further HOC go here
diff --git a/src/containers/WindowSideBarInfoPanel.js b/src/containers/WindowSideBarInfoPanel.js
index 0e2434944b72965b9656fc6a828a77b7ab0f2b43..59b77179421df2a37c4a0b3b85f02a1326dcda20 100644
--- a/src/containers/WindowSideBarInfoPanel.js
+++ b/src/containers/WindowSideBarInfoPanel.js
@@ -1,9 +1,36 @@
 import { compose } from 'redux';
+import { connect } from 'react-redux';
 import { withNamespaces } from 'react-i18next';
 import miradorWithPlugins from '../lib/miradorWithPlugins';
+import {
+  getDestructuredMetadata,
+  getCanvasLabel,
+  getManifestDescription,
+  getManifestTitle,
+  getSelectedCanvas,
+  getWindowManifest,
+} from '../state/selectors';
 import WindowSideBarInfoPanel from '../components/WindowSideBarInfoPanel';
 
+/**
+ * mapStateToProps - to hook up connect
+ * @memberof WindowSideBarInfoPanel
+ * @private
+ */
+const mapStateToProps = (state, { windowId }) => ({
+  canvasLabel: getCanvasLabel(
+    getSelectedCanvas(state, windowId),
+    state.windows[windowId].canvasIndex,
+  ),
+  canvasDescription: getSelectedCanvas(state, windowId).getProperty('description'),
+  canvasMetadata: getDestructuredMetadata(getSelectedCanvas(state, windowId)),
+  manifestLabel: getManifestTitle(getWindowManifest(state, windowId)),
+  manifestDescription: getManifestDescription(getWindowManifest(state, windowId)),
+  manifestMetadata: getDestructuredMetadata(getWindowManifest(state, windowId).manifestation),
+});
+
 const enhance = compose(
+  connect(mapStateToProps, null),
   withNamespaces(),
   miradorWithPlugins,
   // further HOC
diff --git a/src/containers/WindowSideBarPanel.js b/src/containers/WindowSideBarPanel.js
index 1c271c43d54b3cad031d846a3a1a469e879beaf5..81c331df2f704de278cc340496083aac08526a37 100644
--- a/src/containers/WindowSideBarPanel.js
+++ b/src/containers/WindowSideBarPanel.js
@@ -1,4 +1,15 @@
+import { connect } from 'react-redux';
+import { compose } from 'redux';
 import miradorWithPlugins from '../lib/miradorWithPlugins';
 import WindowSideBarPanel from '../components/WindowSideBarPanel';
 
-export default miradorWithPlugins(WindowSideBarPanel);
+/** */
+const mapStateToProps = (state, { windowId }) => ({
+  sideBarPanel: state.windows[windowId].sideBarPanel,
+});
+
+export default compose(
+  connect(mapStateToProps, null),
+  miradorWithPlugins,
+  // further HOC
+)(WindowSideBarPanel);
diff --git a/src/state/selectors/index.js b/src/state/selectors/index.js
index 36b3189cc482135b5f3691906e89d948ff6d416b..b7ed6c2d335bdef94d198de49dafc4fdbe246dbe 100644
--- a/src/state/selectors/index.js
+++ b/src/state/selectors/index.js
@@ -34,6 +34,24 @@ export function getManifestCanvases(manifest) {
   return manifest.manifestation.getSequences()[0].getCanvases();
 }
 
+/**
+* Return the current canvas selected in a window
+* @param {object} state
+* @param {String} windowId
+* @return {Object}
+*/
+export function getSelectedCanvas(state, windowId) {
+  const manifest = getWindowManifest(state, windowId);
+  const { canvasIndex } = state.windows[windowId];
+
+  if (!manifest.manifestation) {
+    return {};
+  }
+
+  return manifest.manifestation.getSequences()[0].getCanvasByIndex(canvasIndex);
+}
+
+
 /** Return position of thumbnail navigation in a certain window.
 * @param {object} state
 * @param {String} windowId
@@ -63,3 +81,44 @@ export function getManifestTitle(manifest) {
 export function getWindowViewType(state, windowId) {
   return state.windows[windowId] && state.windows[windowId].view;
 }
+
+/**
+* Return manifest description
+* @param {object} manifest
+* @return {String}
+*/
+export function getManifestDescription(manifest) {
+  return manifest
+    && manifest.manifestation
+    && manifest.manifestation.getDescription().map(label => label.value)[0];
+}
+
+/**
+* Return canvas label, or alternatively return the given index + 1 to be displayed
+* @param {object} canvas
+* @return {String|Integer}
+*/
+export function getCanvasLabel(canvas, canvasIndex) {
+  return (canvas
+    && canvas.getLabel()
+    && canvas.getLabel().map(label => label.value)[0])
+    || (canvasIndex || 0) + 1;
+}
+
+/**
+* Return canvas metadata in a label / value structure
+* This is a potential seam for pulling the i18n locale from
+* state and plucking out the appropriate language.
+* For now we're just getting the first.
+* @param {object} IIIF Resource
+* @return {Array[Object]}
+*/
+export function getDestructuredMetadata(iiifResoruce) {
+  return (iiifResoruce
+    && iiifResoruce.getMetadata()
+    && iiifResoruce.getMetadata().map(resource => ({
+      label: resource.label[0].value,
+      value: resource.value[0].value,
+    }))
+  );
+}