diff --git a/__tests__/src/selectors/canvases.test.js b/__tests__/src/selectors/canvases.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..ba35f9a865c950e37e6da93ce850ef1957bf45f1
--- /dev/null
+++ b/__tests__/src/selectors/canvases.test.js
@@ -0,0 +1,102 @@
+import manifestFixture019 from '../../fixtures/version-2/019.json';
+import {
+  getSelectedCanvas,
+  getSelectedCanvases,
+} from '../../../src/state/selectors/canvases';
+
+describe('getSelectedCanvas', () => {
+  const state = {
+    windows: {
+      a: {
+        id: 'a',
+        manifestId: 'x',
+        canvasIndex: 1,
+      },
+    },
+    manifests: {
+      x: {
+        id: 'x',
+        json: 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, { windowId: 'a' });
+
+    expect(selectedCanvas.id).toEqual(
+      'https://purl.stanford.edu/fr426cg9537/iiif/canvas/fr426cg9537_1',
+    );
+  });
+
+  it('should return undefined when there is no manifestation to get a canvas from', () => {
+    const selectedCanvas = getSelectedCanvas(noManifestationState, { windowId: 'a' });
+
+    expect(selectedCanvas).toBeUndefined();
+  });
+});
+
+describe('getSelectedCanvases', () => {
+  const state = {
+    windows: {
+      a: {
+        id: 'a',
+        manifestId: 'x',
+        canvasIndex: 1,
+        view: 'book',
+      },
+    },
+    manifests: {
+      x: {
+        id: 'x',
+        json: manifestFixture019,
+      },
+    },
+  };
+
+  const noManifestationState = {
+    windows: {
+      a: {
+        id: 'a',
+        manifestId: 'x',
+        canvasIndex: 1,
+      },
+    },
+    manifests: {
+      x: {
+        id: 'x',
+      },
+    },
+  };
+
+  it('should return canvas groupings based on the canvas index stored window state', () => {
+    const selectedCanvases = getSelectedCanvases(state, { windowId: 'a' });
+
+    expect(selectedCanvases.length).toEqual(2);
+    expect(selectedCanvases.map(canvas => canvas.id)).toEqual([
+      'https://purl.stanford.edu/fr426cg9537/iiif/canvas/fr426cg9537_1',
+      'https://purl.stanford.edu/rz176rt6531/iiif/canvas/rz176rt6531_1',
+    ]);
+  });
+
+  it('should return undefined when there is no manifestation to get a canvas from', () => {
+    const selectedCanvas = getSelectedCanvases(noManifestationState, { windowId: 'a' });
+
+    expect(selectedCanvas).toBeUndefined();
+  });
+});
diff --git a/__tests__/src/selectors/index.test.js b/__tests__/src/selectors/index.test.js
index a98295d5a03f5c8c02c6953dd6739a9e26847803..fdd9ae417dffce6bafbda95487853d8e2d2dde61 100644
--- a/__tests__/src/selectors/index.test.js
+++ b/__tests__/src/selectors/index.test.js
@@ -6,20 +6,12 @@ import manifestFixtureWithAProvider from '../../fixtures/version-3/with_a_provid
 import {
   getCanvasLabel,
   getCompanionWindowForPosition,
-  getDestructuredMetadata,
   getAnnotationResourcesByMotivation,
   getIdAndContentOfResources,
   getLanguagesFromConfigWithCurrent,
   getSelectedCanvas,
   getSelectedCanvases,
-  getManifest,
-  getManifestLogo,
-  getManifestCanvases,
-  getManifestDescription,
   getThumbnailNavigationPosition,
-  getManifestProvider,
-  getManifestTitle,
-  getManifestThumbnail,
   getSelectedAnnotationIds,
   getSelectedTargetAnnotations,
   getSelectedTargetsAnnotations,
@@ -27,123 +19,11 @@ import {
   getWindowViewType,
   getIdAndLabelOfCanvases,
   getCompanionWindowsOfWindow,
-  getManifestMetadata,
   getWindowTitles,
 } from '../../../src/state/selectors';
 import Annotation from '../../../src/lib/Annotation';
 import AnnotationResource from '../../../src/lib/AnnotationResource';
 
-
-describe('getManifest()', () => {
-  const state = {
-    windows: {
-      a: { id: 'a', manifestId: 'x' },
-      b: { id: 'b', manifestId: 'y' },
-      c: { id: 'c' },
-    },
-    manifests: {
-      x: { id: 'x' },
-    },
-  };
-
-  it('should return the manifest of a certain id', () => {
-    const received = getManifest(state, { manifestId: 'x' });
-    const expected = { id: 'x' };
-    expect(received).toEqual(expected);
-  });
-
-
-  it('should return the manifest of a certain window', () => {
-    const received = getManifest(state, { windowId: 'a' });
-    const expected = { id: 'x' };
-    expect(received).toEqual(expected);
-  });
-
-  it('should return undefined if window doesnt exist', () => {
-    const received = getManifest(state, { windowId: 'unknown' });
-    expect(received).toBeUndefined();
-  });
-
-  it('should return undefined if window has no manifest id', () => {
-    const received = getManifest(state, { windowId: 'c' });
-    expect(received).toBeUndefined();
-  });
-
-  it('should return undefined if manifest does not exist', () => {
-    const received = getManifest(state, { windowId: 'b' });
-    expect(received).toBeUndefined();
-  });
-});
-
-describe('getManifestLogo()', () => {
-  it('should return manifest logo id', () => {
-    const received = getManifestLogo({ manifests: { x: { json: manifestFixture001 } } }, { manifestId: 'x' });
-    expect(received).toEqual(manifestFixture001.logo['@id']);
-  });
-
-  it('should return null if manifest has no logo', () => {
-    const received = getManifestLogo({ manifests: { x: {} } }, { manifestId: 'x' });
-    expect(received).toBeUndefined();
-  });
-});
-
-describe('getManifestThumbnail()', () => {
-  it('should return manifest thumbnail id', () => {
-    const state = { manifests: { x: { json: manifestFixture001 } } };
-    const received = getManifestThumbnail(state, { manifestId: 'x' });
-    expect(received).toEqual(manifestFixture001.thumbnail['@id']);
-  });
-
-  it('returns the first canvas thumbnail id', () => {
-    const manifest = {
-      '@context': 'http://iiif.io/api/presentation/2/context.json',
-      '@id':
-       'http://iiif.io/api/presentation/2.1/example/fixtures/19/manifest.json',
-      '@type': 'sc:Manifest',
-      sequences: [
-        {
-          canvases: [
-            {
-              thumbnail: { id: 'xyz' },
-            },
-          ],
-        },
-      ],
-    };
-
-    const state = { manifests: { x: { json: manifest } } };
-    const received = getManifestThumbnail(state, { manifestId: 'x' });
-    expect(received).toEqual('xyz');
-  });
-
-  it('returns a thumbnail sized image url from the first canvas', () => {
-    const state = { manifests: { x: { json: manifestFixture019 } } };
-    const received = getManifestThumbnail(state, { manifestId: 'x' });
-    expect(received).toEqual('https://stacks.stanford.edu/image/iiif/hg676jb4964%2F0380_796-44/full/,80/0/default.jpg');
-  });
-
-  it('should return null if manifest has no thumbnail', () => {
-    const state = { manifests: { x: {} } };
-    const received = getManifestThumbnail(state, { manifestId: 'x' });
-    expect(received).toBeNull();
-  });
-});
-
-describe('getManifestCanvases', () => {
-  it('returns an empty array if the manifestation is not loaded', () => {
-    const state = { manifests: { x: {} } };
-    const received = getManifestCanvases(state, { manifestId: 'x' });
-    expect(received).toEqual([]);
-  });
-
-  it('returns canvases from the manifest', () => {
-    const state = { manifests: { x: { json: manifestFixture001 } } };
-    const received = getManifestCanvases(state, { manifestId: 'x' });
-    expect(received.length).toBe(1);
-    expect(received[0].id).toBe('https://iiif.bodleian.ox.ac.uk/iiif/canvas/9cca8fdd-4a61-4429-8ac1-f648764b4d6d.json');
-  });
-});
-
 describe('getThumbnailNavigationPosition', () => {
   const state = {
     windows: {
@@ -171,42 +51,6 @@ describe('getThumbnailNavigationPosition', () => {
   });
 });
 
-describe('getManifestTitle', () => {
-  it('should return manifest title', () => {
-    const state = { manifests: { x: { json: manifestFixture001 } } };
-    const received = getManifestTitle(state, { manifestId: 'x' });
-    expect(received).toBe('Bodleian Library Human Freaks 2 (33)');
-  });
-
-  it('should return undefined if manifest undefined', () => {
-    const received = getManifestTitle({ manifests: {} }, { manifestId: 'x' });
-    expect(received).toBeUndefined();
-  });
-});
-
-describe('getWindowTitles', () => {
-  it('should return manifest titles for the open windows', () => {
-    const state = {
-      windows: {
-        a: { manifestId: 'amanifest' },
-        b: { manifestId: 'bmanifest' },
-      },
-      manifests: {
-        amanifest: { json: manifestFixture001 },
-        bmanifest: { json: manifestFixture002 },
-        cmanifest: { json: manifestFixture019 },
-      },
-    };
-
-    const received = getWindowTitles(state);
-
-    expect(received).toEqual({
-      a: 'Bodleian Library Human Freaks 2 (33)',
-      b: 'Test 2 Manifest: Metadata Pairs',
-    });
-  });
-});
-
 describe('getWindowViewType', () => {
   const state = {
     windows: {
@@ -231,128 +75,6 @@ describe('getWindowViewType', () => {
   });
 });
 
-describe('getManifestDescription', () => {
-  it('should return manifest description', () => {
-    const state = { manifests: { x: { json: manifestFixture001 } } };
-    const received = getManifestDescription(state, { manifestId: 'x' });
-    expect(received).toBe('[Handbill of Mr. Becket, [1787] ]');
-  });
-
-  it('should return undefined if manifest undefined', () => {
-    const received = getManifestDescription({ manifests: {} }, { manifestId: 'x' });
-    expect(received).toBeUndefined();
-  });
-});
-
-describe('getManifestProvider', () => {
-  it('should return manifest provider label', () => {
-    const state = { manifests: { x: { json: manifestFixtureWithAProvider } } };
-    const received = getManifestProvider(state, { manifestId: 'x' });
-    expect(received).toBe('Example Organization');
-  });
-
-  it('should return undefined if manifest undefined', () => {
-    const received = getManifestProvider({ manifests: {} }, { manifestId: 'x' });
-    expect(received).toBeUndefined();
-  });
-});
-describe('getSelectedCanvas', () => {
-  const state = {
-    windows: {
-      a: {
-        id: 'a',
-        manifestId: 'x',
-        canvasIndex: 1,
-      },
-    },
-    manifests: {
-      x: {
-        id: 'x',
-        json: 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, { windowId: 'a' });
-
-    expect(selectedCanvas.id).toEqual(
-      'https://purl.stanford.edu/fr426cg9537/iiif/canvas/fr426cg9537_1',
-    );
-  });
-
-  it('should return undefined when there is no manifestation to get a canvas from', () => {
-    const selectedCanvas = getSelectedCanvas(noManifestationState, { windowId: 'a' });
-
-    expect(selectedCanvas).toBeUndefined();
-  });
-});
-
-describe('getSelectedCanvases', () => {
-  const state = {
-    windows: {
-      a: {
-        id: 'a',
-        manifestId: 'x',
-        canvasIndex: 1,
-        view: 'book',
-      },
-    },
-    manifests: {
-      x: {
-        id: 'x',
-        json: manifestFixture019,
-      },
-    },
-  };
-
-  const noManifestationState = {
-    windows: {
-      a: {
-        id: 'a',
-        manifestId: 'x',
-        canvasIndex: 1,
-      },
-    },
-    manifests: {
-      x: {
-        id: 'x',
-      },
-    },
-  };
-
-  it('should return canvas groupings based on the canvas index stored window state', () => {
-    const selectedCanvases = getSelectedCanvases(state, { windowId: 'a' });
-
-    expect(selectedCanvases.length).toEqual(2);
-    expect(selectedCanvases.map(canvas => canvas.id)).toEqual([
-      'https://purl.stanford.edu/fr426cg9537/iiif/canvas/fr426cg9537_1',
-      'https://purl.stanford.edu/rz176rt6531/iiif/canvas/rz176rt6531_1',
-    ]);
-  });
-
-  it('should return undefined when there is no manifestation to get a canvas from', () => {
-    const selectedCanvas = getSelectedCanvases(noManifestationState, { windowId: 'a' });
-
-    expect(selectedCanvas).toBeUndefined();
-  });
-});
-
 describe('getCanvasLabel', () => {
   it('should return label of the canvas', () => {
     const canvas = manifesto
@@ -375,45 +97,6 @@ describe('getCanvasLabel', () => {
   });
 });
 
-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([]);
-  });
-});
-
-describe('getManifestMetadata', () => {
-  it('should return the first value of label/value attributes for each object in the array ', () => {
-    const state = { manifests: { x: { json: manifestFixture002 } } };
-    const received = getManifestMetadata(state, { manifestId: 'x' });
-    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([]);
-  });
-});
 
 describe('getSelectedTargetAnnotations', () => {
   it('returns annotations for the given canvasId that have resources', () => {
diff --git a/__tests__/src/selectors/manifests.test.js b/__tests__/src/selectors/manifests.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..cdebc905d6eb9116fb97dc18978febb78e2075d1
--- /dev/null
+++ b/__tests__/src/selectors/manifests.test.js
@@ -0,0 +1,205 @@
+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 manifestFixtureWithAProvider from '../../fixtures/version-3/with_a_provider.json';
+import {
+  getDestructuredMetadata,
+  getManifest,
+  getManifestLogo,
+  getManifestCanvases,
+  getManifestDescription,
+  getManifestProvider,
+  getManifestTitle,
+  getManifestThumbnail,
+  getManifestMetadata,
+} from '../../../src/state/selectors/manifests';
+
+
+describe('getManifest()', () => {
+  const state = {
+    windows: {
+      a: { id: 'a', manifestId: 'x' },
+      b: { id: 'b', manifestId: 'y' },
+      c: { id: 'c' },
+    },
+    manifests: {
+      x: { id: 'x' },
+    },
+  };
+
+  it('should return the manifest of a certain id', () => {
+    const received = getManifest(state, { manifestId: 'x' });
+    const expected = { id: 'x' };
+    expect(received).toEqual(expected);
+  });
+
+
+  it('should return the manifest of a certain window', () => {
+    const received = getManifest(state, { windowId: 'a' });
+    const expected = { id: 'x' };
+    expect(received).toEqual(expected);
+  });
+
+  it('should return undefined if window doesnt exist', () => {
+    const received = getManifest(state, { windowId: 'unknown' });
+    expect(received).toBeUndefined();
+  });
+
+  it('should return undefined if window has no manifest id', () => {
+    const received = getManifest(state, { windowId: 'c' });
+    expect(received).toBeUndefined();
+  });
+
+  it('should return undefined if manifest does not exist', () => {
+    const received = getManifest(state, { windowId: 'b' });
+    expect(received).toBeUndefined();
+  });
+});
+
+describe('getManifestLogo()', () => {
+  it('should return manifest logo id', () => {
+    const received = getManifestLogo({ manifests: { x: { json: manifestFixture001 } } }, { manifestId: 'x' });
+    expect(received).toEqual(manifestFixture001.logo['@id']);
+  });
+
+  it('should return null if manifest has no logo', () => {
+    const received = getManifestLogo({ manifests: { x: {} } }, { manifestId: 'x' });
+    expect(received).toBeUndefined();
+  });
+});
+
+describe('getManifestThumbnail()', () => {
+  it('should return manifest thumbnail id', () => {
+    const state = { manifests: { x: { json: manifestFixture001 } } };
+    const received = getManifestThumbnail(state, { manifestId: 'x' });
+    expect(received).toEqual(manifestFixture001.thumbnail['@id']);
+  });
+
+  it('returns the first canvas thumbnail id', () => {
+    const manifest = {
+      '@context': 'http://iiif.io/api/presentation/2/context.json',
+      '@id':
+       'http://iiif.io/api/presentation/2.1/example/fixtures/19/manifest.json',
+      '@type': 'sc:Manifest',
+      sequences: [
+        {
+          canvases: [
+            {
+              thumbnail: { id: 'xyz' },
+            },
+          ],
+        },
+      ],
+    };
+
+    const state = { manifests: { x: { json: manifest } } };
+    const received = getManifestThumbnail(state, { manifestId: 'x' });
+    expect(received).toEqual('xyz');
+  });
+
+  it('returns a thumbnail sized image url from the first canvas', () => {
+    const state = { manifests: { x: { json: manifestFixture019 } } };
+    const received = getManifestThumbnail(state, { manifestId: 'x' });
+    expect(received).toEqual('https://stacks.stanford.edu/image/iiif/hg676jb4964%2F0380_796-44/full/,80/0/default.jpg');
+  });
+
+  it('should return null if manifest has no thumbnail', () => {
+    const state = { manifests: { x: {} } };
+    const received = getManifestThumbnail(state, { manifestId: 'x' });
+    expect(received).toBeNull();
+  });
+});
+
+describe('getManifestCanvases', () => {
+  it('returns an empty array if the manifestation is not loaded', () => {
+    const state = { manifests: { x: {} } };
+    const received = getManifestCanvases(state, { manifestId: 'x' });
+    expect(received).toEqual([]);
+  });
+
+  it('returns canvases from the manifest', () => {
+    const state = { manifests: { x: { json: manifestFixture001 } } };
+    const received = getManifestCanvases(state, { manifestId: 'x' });
+    expect(received.length).toBe(1);
+    expect(received[0].id).toBe('https://iiif.bodleian.ox.ac.uk/iiif/canvas/9cca8fdd-4a61-4429-8ac1-f648764b4d6d.json');
+  });
+});
+
+describe('getManifestTitle', () => {
+  it('should return manifest title', () => {
+    const state = { manifests: { x: { json: manifestFixture001 } } };
+    const received = getManifestTitle(state, { manifestId: 'x' });
+    expect(received).toBe('Bodleian Library Human Freaks 2 (33)');
+  });
+
+  it('should return undefined if manifest undefined', () => {
+    const received = getManifestTitle({ manifests: {} }, { manifestId: 'x' });
+    expect(received).toBeUndefined();
+  });
+});
+
+describe('getManifestDescription', () => {
+  it('should return manifest description', () => {
+    const state = { manifests: { x: { json: manifestFixture001 } } };
+    const received = getManifestDescription(state, { manifestId: 'x' });
+    expect(received).toBe('[Handbill of Mr. Becket, [1787] ]');
+  });
+
+  it('should return undefined if manifest undefined', () => {
+    const received = getManifestDescription({ manifests: {} }, { manifestId: 'x' });
+    expect(received).toBeUndefined();
+  });
+});
+
+describe('getManifestProvider', () => {
+  it('should return manifest provider label', () => {
+    const state = { manifests: { x: { json: manifestFixtureWithAProvider } } };
+    const received = getManifestProvider(state, { manifestId: 'x' });
+    expect(received).toBe('Example Organization');
+  });
+
+  it('should return undefined if manifest undefined', () => {
+    const received = getManifestProvider({ manifests: {} }, { manifestId: 'x' });
+    expect(received).toBeUndefined();
+  });
+});
+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([]);
+  });
+});
+
+describe('getManifestMetadata', () => {
+  it('should return the first value of label/value attributes for each object in the array ', () => {
+    const state = { manifests: { x: { json: manifestFixture002 } } };
+    const received = getManifestMetadata(state, { manifestId: 'x' });
+    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/__tests__/src/selectors/windows.test.js b/__tests__/src/selectors/windows.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..996599b87edb5ddffc1cf10f2c96cbb12c6144aa
--- /dev/null
+++ b/__tests__/src/selectors/windows.test.js
@@ -0,0 +1,30 @@
+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 {
+  getWindowTitles,
+} from '../../../src/state/selectors/windows';
+
+
+describe('getWindowTitles', () => {
+  it('should return manifest titles for the open windows', () => {
+    const state = {
+      windows: {
+        a: { manifestId: 'amanifest' },
+        b: { manifestId: 'bmanifest' },
+      },
+      manifests: {
+        amanifest: { json: manifestFixture001 },
+        bmanifest: { json: manifestFixture002 },
+        cmanifest: { json: manifestFixture019 },
+      },
+    };
+
+    const received = getWindowTitles(state);
+
+    expect(received).toEqual({
+      a: 'Bodleian Library Human Freaks 2 (33)',
+      b: 'Test 2 Manifest: Metadata Pairs',
+    });
+  });
+});
diff --git a/src/state/selectors/canvases.js b/src/state/selectors/canvases.js
new file mode 100644
index 0000000000000000000000000000000000000000..26d74e5dac2ca23be28bc48141b0a56c37e0f73e
--- /dev/null
+++ b/src/state/selectors/canvases.js
@@ -0,0 +1,43 @@
+import { createSelector } from 'reselect';
+import CanvasGroupings from '../../lib/CanvasGroupings';
+import { getManifestoInstance } from './manifests';
+
+/**
+* Return the current canvas selected in a window
+* @param {object} state
+* @param {object} props
+* @param {string} props.manifestId
+* @param {string} props.windowId
+* @return {Object}
+*/
+export const getSelectedCanvas = createSelector(
+  [
+    getManifestoInstance,
+    (state, { windowId }) => state.windows[windowId].canvasIndex,
+  ],
+  (manifest, canvasIndex) => manifest
+    && manifest
+      .getSequences()[0]
+      .getCanvasByIndex(canvasIndex),
+);
+
+/**
+* Return the current canvases selected in a window
+* For book view returns 2, for single returns 1
+* @param {object} state
+* @param {object} props
+* @param {string} props.manifestId
+* @param {string} props.windowId
+* @return {Array}
+*/
+export const getSelectedCanvases = createSelector(
+  [
+    getManifestoInstance,
+    (state, { windowId }) => state.windows[windowId],
+  ],
+  (manifest, { canvasIndex, view }) => manifest
+    && new CanvasGroupings(
+      manifest.getSequences()[0].getCanvases(),
+      view,
+    ).getCanvases(canvasIndex),
+);
diff --git a/src/state/selectors/index.js b/src/state/selectors/index.js
index 4665330727c3ecbbe2f053a9ff915763b3efa9ed..c51fdf2df3a9c7a298bffb59357da71d29a90c83 100644
--- a/src/state/selectors/index.js
+++ b/src/state/selectors/index.js
@@ -1,117 +1,10 @@
-import { createSelector } from 'reselect';
 import filter from 'lodash/filter';
 import flatten from 'lodash/flatten';
-import manifesto, { LanguageMap } from 'manifesto.js';
 import Annotation from '../../lib/Annotation';
-import ManifestoCanvas from '../../lib/ManifestoCanvas';
-import CanvasGroupings from '../../lib/CanvasGroupings';
 
-/** Get the relevant manifest information */
-export function getManifest(state, { manifestId, windowId }) {
-  return state.manifests[
-    manifestId
-    || (windowId && state.windows[windowId] && state.windows[windowId].manifestId)
-  ];
-}
-
-/** Instantiate a manifesto instance */
-export const getManifestoInstance = createSelector(
-  [getManifest],
-  manifest => manifest && manifest.json && manifesto.create(manifest.json),
-);
-
-/**
- * Get the logo for a manifest
- * @param {object} state
- * @param {object} props
- * @param {string} props.manifestId
- * @param {string} props.windowId
- * @return {String|null}
- */
-export const getManifestLogo = createSelector(
-  [getManifestoInstance],
-  manifest => manifest && manifest.getLogo(),
-);
-
-/**
-* Return the IIIF v3 provider of a manifest or null
-* @param {object} state
-* @param {object} props
-* @param {string} props.manifestId
-* @param {string} props.windowId
-* @return {String|null}
-*/
-export const getManifestProvider = createSelector(
-  [getManifestoInstance],
-  manifest => manifest
-    && manifest.getProperty('provider')
-    && manifest.getProperty('provider')[0].label
-    && LanguageMap.parse(manifest.getProperty('provider')[0].label, manifest.options.locale).map(label => label.value)[0],
-);
-
-/**
-* Return the supplied thumbnail for a manifest or null
-* @param {object} state
-* @param {object} props
-* @param {string} props.manifestId
-* @param {string} props.windowId
-* @return {String|null}
-*/
-export function getManifestThumbnail(state, props) {
-  /** */
-  function getTopLevelManifestThumbnail() {
-    const manifest = getManifestoInstance(state, props);
-
-    return manifest
-      && manifest.getThumbnail()
-      && manifest.getThumbnail().id;
-  }
-
-  /** */
-  function getFirstCanvasThumbnail() {
-    const canvases = getManifestCanvases(state, props);
-
-    return canvases.length > 0 && canvases[0].getThumbnail() && canvases[0].getThumbnail().id;
-  }
-
-  /** */
-  function generateThumbnailFromFirstCanvas() {
-    const canvases = getManifestCanvases(state, props);
-
-    if (canvases.length === 0) return null;
-
-    const manifestoCanvas = new ManifestoCanvas(canvases[0]);
-
-    return manifestoCanvas.thumbnail(null, 80);
-  }
-
-  return getTopLevelManifestThumbnail()
-    || getFirstCanvasThumbnail()
-    || generateThumbnailFromFirstCanvas();
-}
-
-/**
-* Return the logo of a manifest or null
-* @param {object} state
-* @param {object} props
-* @param {string} props.manifestId
-* @param {string} props.windowId
-* @return {String|null}
-*/
-export const getManifestCanvases = createSelector(
-  [getManifestoInstance],
-  (manifest) => {
-    if (!manifest) {
-      return [];
-    }
-
-    if (!manifest.getSequences || !manifest.getSequences()[0]) {
-      return [];
-    }
-
-    return manifest.getSequences()[0].getCanvases();
-  },
-);
+export * from './canvases';
+export * from './manifests';
+export * from './windows';
 
 /**
 * Return ids and labels of canvases
@@ -125,46 +18,6 @@ export function getIdAndLabelOfCanvases(canvases) {
   }));
 }
 
-/**
-* Return the current canvas selected in a window
-* @param {object} state
-* @param {object} props
-* @param {string} props.manifestId
-* @param {string} props.windowId
-* @return {Object}
-*/
-export const getSelectedCanvas = createSelector(
-  [
-    getManifestoInstance,
-    (state, { windowId }) => state.windows[windowId].canvasIndex,
-  ],
-  (manifest, canvasIndex) => manifest
-    && manifest
-      .getSequences()[0]
-      .getCanvasByIndex(canvasIndex),
-);
-
-/**
-* Return the current canvases selected in a window
-* For book view returns 2, for single returns 1
-* @param {object} state
-* @param {object} props
-* @param {string} props.manifestId
-* @param {string} props.windowId
-* @return {Array}
-*/
-export const getSelectedCanvases = createSelector(
-  [
-    getManifestoInstance,
-    (state, { windowId }) => state.windows[windowId],
-  ],
-  (manifest, { canvasIndex, view }) => manifest
-    && new CanvasGroupings(
-      manifest.getSequences()[0].getCanvases(),
-      view,
-    ).getCanvases(canvasIndex),
-);
-
 /**
 * Return annotations for an array of targets
 * @param {object} state
@@ -235,34 +88,6 @@ export function getThumbnailNavigationPosition(state, windowId) {
     && state.companionWindows[state.windows[windowId].thumbnailNavigationId].position;
 }
 
-/**
-* Return manifest title
-* @param {object} state
-* @param {object} props
-* @param {string} props.manifestId
-* @param {string} props.windowId
-* @return {String}
-*/
-export const getManifestTitle = createSelector(
-  [getManifestoInstance],
-  manifest => manifest
-    && manifest.getLabel().map(label => label.value)[0],
-);
-
-/**
- * Return the manifest titles for all open windows
- * @param {object} state
- * @return {object}
- */
-export function getWindowTitles(state) {
-  const result = {};
-
-  Object.keys(state.windows).forEach((windowId) => {
-    result[windowId] = getManifestTitle(state, { windowId });
-  });
-
-  return result;
-}
 
 /** Return type of view in a certain window.
 * @param {object} state
@@ -275,20 +100,6 @@ export function getWindowViewType(state, windowId) {
   return state.windows[windowId] && state.windows[windowId].view;
 }
 
-/**
-* Return manifest description
-* @param {object} state
-* @param {object} props
-* @param {string} props.manifestId
-* @param {string} props.windowId
-* @return {String}
-*/
-export const getManifestDescription = createSelector(
-  [getManifestoInstance],
-  manifest => manifest
-    && manifest.getDescription().map(label => label.value)[0],
-);
-
 /**
 * Return canvas label, or alternatively return the given index + 1 to be displayed
 * @param {object} canvas
@@ -304,36 +115,6 @@ export function getCanvasLabel(canvas, canvasIndex) {
   return String(canvasIndex + 1);
 }
 
-/**
-* Return 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} Manifesto IIIF Resource (e.g. canvas, manifest)
-* @return {Array[Object]}
-*/
-export function getDestructuredMetadata(iiifResource) {
-  return (iiifResource
-    && iiifResource.getMetadata().map(labelValuePair => ({
-      label: labelValuePair.getLabel(),
-      value: labelValuePair.getValue(),
-    }))
-  );
-}
-
-/**
- * Return manifest metadata in a label / value structure
- * @param {object} state
- * @param {object} props
- * @param {string} props.manifestId
- * @param {string} props.windowId
- * @return {Array[Object]}
- */
-export const getManifestMetadata = createSelector(
-  [getManifestoInstance],
-  manifest => manifest && getDestructuredMetadata(manifest),
-);
-
 /**
 * Return canvas description
 * @param {object} canvas
diff --git a/src/state/selectors/manifests.js b/src/state/selectors/manifests.js
new file mode 100644
index 0000000000000000000000000000000000000000..2d57c9607f1d696b19c279bf7c3b31b877cec9e9
--- /dev/null
+++ b/src/state/selectors/manifests.js
@@ -0,0 +1,168 @@
+import { createSelector } from 'reselect';
+import manifesto, { LanguageMap } from 'manifesto.js';
+import ManifestoCanvas from '../../lib/ManifestoCanvas';
+
+/** Get the relevant manifest information */
+export function getManifest(state, { manifestId, windowId }) {
+  return state.manifests[
+    manifestId
+    || (windowId && state.windows[windowId] && state.windows[windowId].manifestId)
+  ];
+}
+
+/** Instantiate a manifesto instance */
+export const getManifestoInstance = createSelector(
+  [getManifest],
+  manifest => manifest && manifest.json && manifesto.create(manifest.json),
+);
+
+/**
+ * Get the logo for a manifest
+ * @param {object} state
+ * @param {object} props
+ * @param {string} props.manifestId
+ * @param {string} props.windowId
+ * @return {String|null}
+ */
+export const getManifestLogo = createSelector(
+  [getManifestoInstance],
+  manifest => manifest && manifest.getLogo(),
+);
+
+/**
+* Return the IIIF v3 provider of a manifest or null
+* @param {object} state
+* @param {object} props
+* @param {string} props.manifestId
+* @param {string} props.windowId
+* @return {String|null}
+*/
+export const getManifestProvider = createSelector(
+  [getManifestoInstance],
+  manifest => manifest
+    && manifest.getProperty('provider')
+    && manifest.getProperty('provider')[0].label
+    && LanguageMap.parse(manifest.getProperty('provider')[0].label, manifest.options.locale).map(label => label.value)[0],
+);
+
+/**
+* Return the supplied thumbnail for a manifest or null
+* @param {object} state
+* @param {object} props
+* @param {string} props.manifestId
+* @param {string} props.windowId
+* @return {String|null}
+*/
+export function getManifestThumbnail(state, props) {
+  /** */
+  function getTopLevelManifestThumbnail() {
+    const manifest = getManifestoInstance(state, props);
+
+    return manifest
+      && manifest.getThumbnail()
+      && manifest.getThumbnail().id;
+  }
+
+  /** */
+  function getFirstCanvasThumbnail() {
+    const canvases = getManifestCanvases(state, props);
+
+    return canvases.length > 0 && canvases[0].getThumbnail() && canvases[0].getThumbnail().id;
+  }
+
+  /** */
+  function generateThumbnailFromFirstCanvas() {
+    const canvases = getManifestCanvases(state, props);
+
+    if (canvases.length === 0) return null;
+
+    const manifestoCanvas = new ManifestoCanvas(canvases[0]);
+
+    return manifestoCanvas.thumbnail(null, 80);
+  }
+
+  return getTopLevelManifestThumbnail()
+    || getFirstCanvasThumbnail()
+    || generateThumbnailFromFirstCanvas();
+}
+
+/**
+* Return the logo of a manifest or null
+* @param {object} state
+* @param {object} props
+* @param {string} props.manifestId
+* @param {string} props.windowId
+* @return {String|null}
+*/
+export const getManifestCanvases = createSelector(
+  [getManifestoInstance],
+  (manifest) => {
+    if (!manifest) {
+      return [];
+    }
+
+    if (!manifest.getSequences || !manifest.getSequences()[0]) {
+      return [];
+    }
+
+    return manifest.getSequences()[0].getCanvases();
+  },
+);
+
+/**
+* Return manifest title
+* @param {object} state
+* @param {object} props
+* @param {string} props.manifestId
+* @param {string} props.windowId
+* @return {String}
+*/
+export const getManifestTitle = createSelector(
+  [getManifestoInstance],
+  manifest => manifest
+    && manifest.getLabel().map(label => label.value)[0],
+);
+
+/**
+* Return manifest description
+* @param {object} state
+* @param {object} props
+* @param {string} props.manifestId
+* @param {string} props.windowId
+* @return {String}
+*/
+export const getManifestDescription = createSelector(
+  [getManifestoInstance],
+  manifest => manifest
+    && manifest.getDescription().map(label => label.value)[0],
+);
+
+/**
+* Return 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} Manifesto IIIF Resource (e.g. canvas, manifest)
+* @return {Array[Object]}
+*/
+export function getDestructuredMetadata(iiifResource) {
+  return (iiifResource
+    && iiifResource.getMetadata().map(labelValuePair => ({
+      label: labelValuePair.getLabel(),
+      value: labelValuePair.getValue(),
+    }))
+  );
+}
+
+/**
+ * Return manifest metadata in a label / value structure
+ * @param {object} state
+ * @param {object} props
+ * @param {string} props.manifestId
+ * @param {string} props.windowId
+ * @return {Array[Object]}
+ */
+export const getManifestMetadata = createSelector(
+  [getManifestoInstance],
+  manifest => manifest && getDestructuredMetadata(manifest),
+);
diff --git a/src/state/selectors/windows.js b/src/state/selectors/windows.js
new file mode 100644
index 0000000000000000000000000000000000000000..3832c0c3fa549c87ee80d074929435d56e964a2f
--- /dev/null
+++ b/src/state/selectors/windows.js
@@ -0,0 +1,16 @@
+import { getManifestTitle } from './manifests';
+
+/**
+ * Return the manifest titles for all open windows
+ * @param {object} state
+ * @return {object}
+ */
+export function getWindowTitles(state) {
+  const result = {};
+
+  Object.keys(state.windows).forEach((windowId) => {
+    result[windowId] = getManifestTitle(state, { windowId });
+  });
+
+  return result;
+}