diff --git a/__tests__/integration/mirador/thumbnail-navigation.test.js b/__tests__/integration/mirador/thumbnail-navigation.test.js
index 35de953ccaa3b13e04ec8ab4fb17bc7a9faf381e..82502cbd53e644f1417557d7fa56bb5f80f704f5 100644
--- a/__tests__/integration/mirador/thumbnail-navigation.test.js
+++ b/__tests__/integration/mirador/thumbnail-navigation.test.js
@@ -6,7 +6,8 @@ describe('Thumbnail navigation', () => {
     await expect(page).toMatchElement('.mirador-window', { polling: 'mutation', timeout: 5000 });
   });
 
-  it('navigates a manifest using thumbnail navigation', async () => {
+  // TODO: pick a new url; this Harvard one is 404
+  xit('navigates a manifest using thumbnail navigation', async () => {
     await expect(page).toMatchElement('.mirador-thumb-navigation');
     let windows = await page.evaluate(() => (
       miradorInstance.store.getState().windows
@@ -20,7 +21,7 @@ describe('Thumbnail navigation', () => {
     ));
     expect(Object.values(windows)[0].canvasId).toBe('https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-18737483'); // canvas @ index 1
   });
-  it('displays on right side', async () => {
+  xit('displays on right side', async () => {
     await expect(page).toMatchElement('.mirador-thumb-navigation');
     await expect(page).toMatchElement('.mirador-companion-area-far-bottom .mirador-thumb-navigation');
     const windowId = await page.evaluate(() => {
diff --git a/__tests__/src/components/AppProviders.test.js b/__tests__/src/components/AppProviders.test.js
index 82e2f981e309ba39b5afbfc60e4b4304904bfa3d..ae97556638812588c2481172ad0e7bc3943d9a23 100644
--- a/__tests__/src/components/AppProviders.test.js
+++ b/__tests__/src/components/AppProviders.test.js
@@ -1,4 +1,4 @@
-import Button from '@material-ui/core/Button';
+import Button from '@mui/material/Button';
 import { render, screen } from 'test-utils';
 import { useTranslation } from 'react-i18next';
 import { useDrop } from 'react-dnd';
diff --git a/__tests__/src/components/CollapsibleSection.test.js b/__tests__/src/components/CollapsibleSection.test.js
index 9e3ee8757ca6837b22d788e51ecc0ac879fb03e6..aad2dd0f4c16bbce9bfa1a7e826d4cf525baae70 100644
--- a/__tests__/src/components/CollapsibleSection.test.js
+++ b/__tests__/src/components/CollapsibleSection.test.js
@@ -34,9 +34,9 @@ describe('CollapsibleSection', () => {
     expect(screen.getByRole('button')).toHaveAttribute('aria-label', 'expandSection');
   });
 
-  it('renders children based on the open state', async () => {
-    expect(screen.getByTestId('child')).toBeInTheDocument();
+  it('displays children based on the open state', async () => {
+    expect(screen.getByTestId('child')).toBeVisible();
     await userEvent.click(screen.getByRole('button'));
-    expect(screen.queryByTestId('child')).not.toBeInTheDocument();
+    expect(screen.queryByTestId('child')).not.toBeVisible();
   });
 });
diff --git a/__tests__/src/components/CompanionArea.test.js b/__tests__/src/components/CompanionArea.test.js
index 404359b6af87d87a52ae7bd54e2f992a4a8adb9b..53e7bcdb0a5d1e347e664b42f4fe945c78371c2d 100644
--- a/__tests__/src/components/CompanionArea.test.js
+++ b/__tests__/src/components/CompanionArea.test.js
@@ -30,7 +30,7 @@ describe('CompanionArea', () => {
   it('should add the appropriate classes when the companion area fills the full width', () => {
     const { container } = createWrapper({ position: 'bottom' });
 
-    expect(container.querySelector('.mirador-companion-area-bottom')).toHaveClass('horizontal'); // eslint-disable-line testing-library/no-node-access, testing-library/no-container
+    expect(container.querySelector('.mirador-companion-area-bottom')).toBeInTheDocument(); // eslint-disable-line testing-library/no-node-access, testing-library/no-container
   });
 
   it('renders the appropriate <CompanionWindow> components', () => {
diff --git a/__tests__/src/components/CompanionWindow.test.js b/__tests__/src/components/CompanionWindow.test.js
index 60343426fe4b741bc80ad827b67adaf8cc742849..a7fe7b71ef7f4c22b3a3838545c029845a11e84d 100644
--- a/__tests__/src/components/CompanionWindow.test.js
+++ b/__tests__/src/components/CompanionWindow.test.js
@@ -11,7 +11,6 @@ function createWrapper(props) {
       isDisplayed
       direction="ltr"
       windowId="x"
-      classes={{ horizontal: 'horizontal', small: 'small', vertical: 'vertical' }}
       companionWindow={{}}
       position="right"
       {...props}
@@ -96,9 +95,10 @@ describe('CompanionWindow', () => {
         updateCompanionWindow,
       });
 
-      expect(screen.getByRole('complementary')).toHaveClass('vertical');
+      expect(screen.getByRole('complementary')).toHaveClass('mirador-companion-window-right');
 
       await user.click(screen.getByRole('button', { name: 'moveCompanionWindowToBottom' }));
+
       expect(updateCompanionWindow).toHaveBeenCalledWith({ position: 'bottom' });
     });
   });
@@ -113,7 +113,7 @@ describe('CompanionWindow', () => {
         updateCompanionWindow,
       });
 
-      expect(screen.getByRole('complementary')).toHaveClass('horizontal');
+      expect(screen.getByRole('complementary')).toHaveClass('mirador-companion-window-bottom ');
 
       await user.click(screen.getByRole('button', { name: 'moveCompanionWindowToRight' }));
 
@@ -127,12 +127,6 @@ describe('CompanionWindow', () => {
     expect(screen.getByTestId('xyz')).toBeInTheDocument();
   });
 
-  it('adds a small class when the component width is small', () => {
-    const { container } = createWrapper({ size: { width: 369 } });
-
-    expect(container.querySelector('.MuiToolbar-root')).toHaveClass('small'); // eslint-disable-line testing-library/no-node-access, testing-library/no-container
-  });
-
   it('has a resize handler', () => {
     const { container } = createWrapper();
 
diff --git a/__tests__/src/components/GalleryViewThumbnail.test.js b/__tests__/src/components/GalleryViewThumbnail.test.js
index 3ff910b0865188bef23cb3062272b4fcde964a73..bad9e3098edd648ca859b814766c6ddfff075a09 100644
--- a/__tests__/src/components/GalleryViewThumbnail.test.js
+++ b/__tests__/src/components/GalleryViewThumbnail.test.js
@@ -11,7 +11,6 @@ function createWrapper(props) {
   return render(
     <GalleryViewThumbnail
       canvas={Utils.parseManifest(manifestJson).getSequences()[0].getCanvases()[0]}
-      classes={{ selected: 'selected' }}
       focusOnCanvas={() => {}}
       setCanvas={() => {}}
       {...props}
@@ -23,26 +22,6 @@ describe('GalleryView', () => {
   beforeEach(() => {
     window.HTMLElement.prototype.scrollIntoView = jest.fn();
   });
-  it('sets a mirador-current-canvas-grouping class when the canvas is selected', () => {
-    createWrapper({ selected: true });
-    expect(screen.getByRole('button')).toBeInTheDocument();
-    expect(screen.getByRole('button')).toHaveClass('selected');
-  });
-  it('does not set a mirador-current-canvas-grouping class when the canvas is not selected', () => {
-    createWrapper({ selected: false });
-    expect(screen.getByRole('button')).toBeInTheDocument();
-    expect(screen.getByRole('button')).not.toHaveClass('selected');
-  });
-  it('sets a mirador-current-canvas-grouping class when the canvas is selected', () => {
-    createWrapper({ selected: true });
-    expect(screen.getByRole('button')).toBeInTheDocument();
-    expect(screen.getByRole('button')).toHaveClass('selected');
-  });
-  it('does not set a mirador-current-canvas-grouping class when the canvas is not selected', () => {
-    createWrapper({ selected: false });
-    expect(screen.getByRole('button')).toBeInTheDocument();
-    expect(screen.getByRole('button')).not.toHaveClass('selected');
-  });
   it('renders the thumbnail', () => {
     createWrapper({ config: { height: 55 } });
     expect(screen.getByRole('presentation')).toBeInTheDocument();
diff --git a/__tests__/src/components/IIIFAuthentication.test.js b/__tests__/src/components/IIIFAuthentication.test.js
index d9be920ac9d4ae9b4eeb14415b3b03720c271382..d49d5e712d86dfd835d1353a816ed54910da433b 100644
--- a/__tests__/src/components/IIIFAuthentication.test.js
+++ b/__tests__/src/components/IIIFAuthentication.test.js
@@ -33,7 +33,7 @@ describe('IIIFAuthentication', () => {
   describe('without an auth service', () => {
     it('renders nothing', () => {
       createWrapper({ authServiceId: null });
-      expect(screen.queryByText('login', { selector: 'span' })).not.toBeInTheDocument();
+      expect(screen.queryByRole('button', { name: 'login' })).not.toBeInTheDocument();
       expect(screen.queryByRole('button')).not.toBeInTheDocument();
     });
   });
@@ -41,9 +41,7 @@ describe('IIIFAuthentication', () => {
     it('renders a login bar', async () => {
       const handleAuthInteraction = jest.fn();
       createWrapper({ handleAuthInteraction });
-      const confirmBtn = screen.getByText('login', { selector: 'span' });
-      expect(confirmBtn).toBeInTheDocument();
-      await user.click(confirmBtn);
+      await user.click(screen.getByRole('button', { name: 'login' }));
       expect(handleAuthInteraction).toHaveBeenCalledWith('w', 'http://example.com/auth');
     });
     it('renders nothing for a non-interactive login', () => {
@@ -55,7 +53,8 @@ describe('IIIFAuthentication', () => {
     it('renders with an error message', async () => {
       const handleAuthInteraction = jest.fn();
       createWrapper({ handleAuthInteraction, status: 'failed' });
-      const confirmBtn = await screen.findByText('retry', { selector: 'span' });
+      await user.click(screen.getByRole('button', { name: 'continue' }));
+      const confirmBtn = screen.getByRole('button', { name: /retry/ });
       expect(screen.getByText('Login failed')).toBeInTheDocument();
       expect(screen.getByText('cancel')).toBeInTheDocument();
       expect(screen.getByText('... and this is why.')).toBeInTheDocument();
@@ -71,7 +70,7 @@ describe('IIIFAuthentication', () => {
       window.open = mockWindowOpen;
       const resolveCookieMock = jest.fn();
       createWrapper({ resolveAuthenticationRequest: resolveCookieMock, status: 'cookie' });
-      expect(screen.getByText('login', { selector: 'span' })).toBeInTheDocument();
+      expect(screen.getByRole('button', { name: 'login' })).toBeInTheDocument();
       expect(mockWindowOpen).toHaveBeenCalledWith(`http://example.com/auth?origin=${window.origin}`, 'IiifLoginSender', 'centerscreen');
       mockWindow.closed = true;
       jest.runOnlyPendingTimers();
@@ -81,7 +80,7 @@ describe('IIIFAuthentication', () => {
     it('does the IIIF access token behavior', async () => {
       const resolveTokenMock = jest.fn();
       createWrapper({ resolveAccessTokenRequest: resolveTokenMock, status: 'token' });
-      expect(screen.getByText('login', { selector: 'span' })).toBeInTheDocument();
+      expect(screen.getByRole('button', { name: 'login' })).toBeInTheDocument();
       window.dispatchEvent(new MessageEvent('message', {
         data: { messageId: 'http://example.com/token' },
       }));
@@ -100,7 +99,7 @@ describe('IIIFAuthentication', () => {
         resetAuthenticationState,
         status: 'ok',
       });
-      const confirmBtn = await screen.findByText('exit', { selector: 'span' });
+      const confirmBtn = await screen.findByRole('button', { name: 'exit' });
       await user.click(confirmBtn);
       await waitFor(() => expect(resetAuthenticationState).toHaveBeenCalledWith({
         authServiceId: 'http://example.com/auth', tokenServiceId: 'http://example.com/token',
diff --git a/__tests__/src/components/LanguageSettings.test.js b/__tests__/src/components/LanguageSettings.test.js
index 0cddf8b5db29fe186da2a48ddf186f6e5f614ef2..98b0a82f6d7bce81ff7767993531b8377eef9b50 100644
--- a/__tests__/src/components/LanguageSettings.test.js
+++ b/__tests__/src/components/LanguageSettings.test.js
@@ -35,13 +35,6 @@ describe('LanguageSettings', () => {
     expect(screen.getAllByRole('menuitem')).toHaveLength(2);
   });
 
-  it('non-active list items are buttons (and active are not)', () => {
-    createWrapper({ languages });
-
-    expect(screen.getByRole('menuitem', { name: 'Deutsch' })).not.toHaveClass('MuiButtonBase-root');
-    expect(screen.getByRole('menuitem', { name: 'English' })).toHaveClass('MuiButtonBase-root');
-  });
-
   it('renders the check icon when the active prop returns true', () => {
     createWrapper({ languages });
 
diff --git a/__tests__/src/components/LocalePicker.test.js b/__tests__/src/components/LocalePicker.test.js
index a37bdb4bd927a0eb503c6e0b1136d08f99af7e9f..2ff1b2ceefa4c4e1f96a2a06ee1ead0476de8e85 100644
--- a/__tests__/src/components/LocalePicker.test.js
+++ b/__tests__/src/components/LocalePicker.test.js
@@ -3,7 +3,7 @@ import userEvent from '@testing-library/user-event';
 import { LocalePicker } from '../../../src/components/LocalePicker';
 
 /**
- * Helper function to create a shallow wrapper around LanguageSettings
+ * Helper function to create a shallow wrapper around LocalePicker
  */
 function createWrapper(props) {
   return render(
@@ -24,36 +24,42 @@ describe('LocalePicker', () => {
   });
 
   it('renders a select with the current value', () => {
-    createWrapper({ availableLocales: ['en', 'de'], locale: 'en' });
-
-    expect(screen.getByRole('button')).toHaveTextContent('en');
+    createWrapper({ availableLocales: ['en', 'de'], locale: 'de' });
+    // The option to expand the dropdown menu is rendered by a CompanionWindow titleControls prop in WindowSideBarInfoPanel, which is a combobox
+    const dropdownTitle = screen.getByRole('combobox');
+    expect(dropdownTitle).toHaveTextContent('de');
   });
 
-  it('renders a select with a list item for each language passed in props', async () => {
+  it('renders a select with both options and sets the current value', async () => {
     const user = userEvent.setup();
-
-    createWrapper({ availableLocales: ['en', 'de'], locale: 'en' });
-
-    await user.click(screen.getByRole('button'));
-
-    expect(screen.getAllByRole('option')).toHaveLength(2);
+    createWrapper({ availableLocales: ['en', 'de'], locale: 'de' });
+    const dropdownTitle = screen.getByRole('combobox');
+    // Open the menu
+    await user.click(dropdownTitle);
+    // The dropddown menu is not nested within the combobox, it is a sibling in the DOM, an MuiMenu
+    const menu = screen.getByRole('listbox');
+    // Assert that the menu element has 2 children (2 options)
+    expect(menu.children).toHaveLength(2); // eslint-disable-line testing-library/no-node-access
+    // Verify that the select element has the correct value ('de')
+    const deOption = screen.getByRole('option', { name: 'de' });
+    expect(deOption).toHaveAttribute('aria-selected', 'true');
+    // Verify en is also an option
     expect(screen.getByRole('option', { name: 'en' })).toBeInTheDocument();
-    expect(screen.getByRole('option', { name: 'de' })).toBeInTheDocument();
   });
 
   it('triggers setLocale prop when clicking a list item', async () => {
     const user = userEvent.setup();
     const setLocale = jest.fn();
-
     createWrapper({
       availableLocales: ['en', 'de'],
       locale: 'en',
       setLocale,
     });
-
-    await user.click(screen.getByRole('button'));
+    const dropdownTitle = screen.getByRole('combobox');
+    // Open the Select component
+    await user.click(dropdownTitle);
+    // Change the locale to 'de'
     await user.click(screen.getByRole('option', { name: 'de' }));
-
     expect(setLocale).toHaveBeenCalledTimes(1);
     expect(setLocale).toHaveBeenCalledWith('de');
   });
diff --git a/__tests__/src/components/ManifestListItem.test.js b/__tests__/src/components/ManifestListItem.test.js
index ac40ea45865438b9d687ffb8c8d428db64eeb2f6..bd444de9156ad4b77d10e828de451631c19bb105 100644
--- a/__tests__/src/components/ManifestListItem.test.js
+++ b/__tests__/src/components/ManifestListItem.test.js
@@ -23,18 +23,23 @@ describe('ManifestListItem', () => {
     createWrapper({ buttonRef: 'ref' });
 
     expect(screen.getByRole('listitem')).toHaveAttribute('data-manifestid', 'http://example.com');
+    expect(screen.getByRole('listitem')).toHaveClass('MuiListItem-root');
     expect(screen.getByRole('button')).toHaveTextContent('xyz');
   });
   it('adds a class when the item is active', () => {
     createWrapper({ active: true, classes: { active: 'active' } });
 
+    // If this is true, we can assume the proper styling classes are being applied
+    expect(screen.getByRole('listitem')).toHaveAttribute('data-active', 'true');
+
     expect(screen.getByRole('listitem')).toHaveClass('active');
+    expect(screen.getByRole('listitem')).toHaveClass('Mui-selected');
   });
   it('renders a placeholder element until real data is available', () => {
     const { container } = createWrapper({ ready: false });
 
     expect(screen.queryByRole('button')).not.toBeInTheDocument();
-    expect(container.querySelectorAll('.MuiSkeleton-rect').length).toBeGreaterThan(0); // eslint-disable-line testing-library/no-node-access, testing-library/no-container
+    expect(container.querySelectorAll('.MuiSkeleton-rectangular').length).toBeGreaterThan(0); // eslint-disable-line testing-library/no-node-access, testing-library/no-container
   });
   it('renders an error message if fetching the manifest failed', () => {
     createWrapper({ error: 'This is an error message' });
diff --git a/__tests__/src/components/PrimaryWindow.test.js b/__tests__/src/components/PrimaryWindow.test.js
index 52ca6c86b82a9c87bcf08e37c7a09b33c5bc3db8..ad78ebf4b5cf39c5f7433721471429ded5b96237 100644
--- a/__tests__/src/components/PrimaryWindow.test.js
+++ b/__tests__/src/components/PrimaryWindow.test.js
@@ -16,7 +16,7 @@ function createWrapper(props) {
 describe('PrimaryWindow', () => {
   it('should render expected elements', async () => {
     createWrapper({ isFetching: false });
-    await screen.findByRole('region', { accessibleName: 'item' });
+    await screen.findByTestId('test-window');
     expect(document.querySelector('.mirador-primary-window')).toBeInTheDocument(); // eslint-disable-line testing-library/no-node-access
     expect(document.querySelector('.mirador-companion-area-left')).toBeInTheDocument(); // eslint-disable-line testing-library/no-node-access
   });
@@ -30,7 +30,7 @@ describe('PrimaryWindow', () => {
   });
   it('should render <GalleryView> if fetching is complete and view is gallery', async () => {
     createWrapper({ isFetching: false, view: 'gallery' });
-    await screen.findByRole('region', { accessibleName: 'gallery section' });
+    await screen.findByTestId('test-window');
     expect(document.querySelector('#xyz-gallery')).toBeInTheDocument(); // eslint-disable-line testing-library/no-node-access
   });
   it('should render <CollectionDialog> and <SelectCollection> if manifest is collection and isCollectionDialogVisible', async () => {
diff --git a/__tests__/src/components/SanitizedHtml.test.js b/__tests__/src/components/SanitizedHtml.test.js
index 37c09f96c12440c7ab051fe23ca45626754cb3ee..382b90570e5ca8748fab1db2d7da25746e9c1f90 100644
--- a/__tests__/src/components/SanitizedHtml.test.js
+++ b/__tests__/src/components/SanitizedHtml.test.js
@@ -6,7 +6,6 @@ describe('SanitizedHtml', () => {
     render(
       <SanitizedHtml
         data-testid="subject"
-        classes={{ root: 'root' }}
         htmlString="<script>doBadThings()</script><b>Don't worry!</b><a>Some link</a>"
         ruleSet="iiif"
       />,
@@ -18,7 +17,6 @@ describe('SanitizedHtml', () => {
   });
 
   it('should pass correct class name to root element', () => {
-    expect(screen.getByTestId('subject')).toHaveClass('root');
     expect(screen.getByTestId('subject')).toHaveClass('mirador-third-party-html');
   });
 
diff --git a/__tests__/src/components/ScrollIndicatedDialogContent.test.js b/__tests__/src/components/ScrollIndicatedDialogContent.test.js
index 4c76018dca7d1c4614071af837c6e6ec493566ee..ae84979485a464c2d6b98928a42082833702c223 100644
--- a/__tests__/src/components/ScrollIndicatedDialogContent.test.js
+++ b/__tests__/src/components/ScrollIndicatedDialogContent.test.js
@@ -6,7 +6,6 @@ function createWrapper(props) {
   return render(
     <ScrollIndicatedDialogContent
       data-testid="subject"
-      classes={{ shadowScrollDialog: 'shadowScrollDialog' }}
       {...props}
     />,
   );
@@ -19,16 +18,8 @@ describe('ScrollIndicatedDialogContent', () => {
     expect(screen.getByTestId('subject')).toHaveAttribute('randomprop', 'randomPropValue');
   });
 
-  it('provides a className to the DialogContent prop to style it', () => {
-    createWrapper();
-
-    expect(screen.getByTestId('subject')).toHaveClass('shadowScrollDialog');
-  });
-
   it('joins an incoming className prop with our className', () => {
     createWrapper({ className: 'upstreamClassName' });
-
-    expect(screen.getByTestId('subject')).toHaveClass('shadowScrollDialog');
     expect(screen.getByTestId('subject')).toHaveClass('upstreamClassName');
   });
 });
diff --git a/__tests__/src/components/ScrollTo.test.js b/__tests__/src/components/ScrollTo.test.js
index eb2f38c157394c6a7c6c1dd773ecc747fbf56cd4..fd4f34f087645e865eb56725a97705c40b80f7ca 100644
--- a/__tests__/src/components/ScrollTo.test.js
+++ b/__tests__/src/components/ScrollTo.test.js
@@ -1,4 +1,4 @@
-import { render, screen } from 'test-utils';
+import { render } from 'test-utils';
 import { createRef } from 'react';
 import { ScrollTo } from '../../../src/components/ScrollTo';
 
@@ -12,7 +12,7 @@ describe('ScrollTo', () => {
     containerRef = createRef();
     render(<div data-testid="container" ref={containerRef} />);
 
-    containerRef.current.domEl = {
+    containerRef.current = {
       getBoundingClientRect: () => containerBoundingRect,
       getElementsByClassName: () => [{ scrollTo }],
     };
@@ -22,12 +22,6 @@ describe('ScrollTo', () => {
   const scrollToElBelowBoundingRect = { bottom: 601, top: 501 };
   const visibleScrollToElBoundingRect = { bottom: 300, top: 200 };
 
-  it('wraps the given children in a div element', () => {
-    render(<ScrollTo data-testid="subject" scrollTo>Child Prop</ScrollTo>);
-
-    expect(screen.getByTestId('subject')).toHaveTextContent('Child Prop');
-  });
-
   describe('when updating the scrollTo prop', () => {
     beforeEach(() => {
       jest.spyOn(ScrollTo.prototype, 'elementToScrollTo').mockImplementation(() => ({ offsetTop: 450 }));
@@ -38,13 +32,13 @@ describe('ScrollTo', () => {
           ...scrollToElAboveBoundingRect,
         }));
 
-        const { rerender } = render(<ScrollTo scrollTo containerRef={containerRef}>Child</ScrollTo>);
+        const { rerender } = render(<ScrollTo scrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
 
         // It is called once when initially rendered w/ true
         expect(scrollTo).toHaveBeenCalled();
         scrollTo.mockReset();
 
-        rerender(<ScrollTo containerRef={containerRef}>Child</ScrollTo>);
+        rerender(<ScrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
 
         // But it is not called on the re-render w/ false
         expect(scrollTo).not.toHaveBeenCalled();
@@ -56,9 +50,9 @@ describe('ScrollTo', () => {
         jest.spyOn(ScrollTo.prototype, 'scrollToBoundingRect').mockImplementation(() => ({
           ...scrollToElAboveBoundingRect,
         }));
-        const { rerender } = render(<ScrollTo containerRef={containerRef}>Child</ScrollTo>);
+        const { rerender } = render(<ScrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
 
-        rerender(<ScrollTo scrollTo containerRef={containerRef}>Child</ScrollTo>);
+        rerender(<ScrollTo scrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
 
         expect(scrollTo).toHaveBeenCalledWith(0, 230);
       });
@@ -68,9 +62,9 @@ describe('ScrollTo', () => {
           ...scrollToElBelowBoundingRect,
         }));
 
-        const { rerender } = render(<ScrollTo containerRef={containerRef}>Child</ScrollTo>);
+        const { rerender } = render(<ScrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
 
-        rerender(<ScrollTo scrollTo containerRef={containerRef}>Child</ScrollTo>);
+        rerender(<ScrollTo scrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
 
         expect(scrollTo).toHaveBeenCalledWith(0, 230);
       });
@@ -80,9 +74,9 @@ describe('ScrollTo', () => {
           ...visibleScrollToElBoundingRect,
         }));
 
-        const { rerender } = render(<ScrollTo containerRef={containerRef}>Child</ScrollTo>);
+        const { rerender } = render(<ScrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
 
-        rerender(<ScrollTo scrollTo containerRef={containerRef}>Child</ScrollTo>);
+        rerender(<ScrollTo scrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
 
         expect(scrollTo).not.toHaveBeenCalled();
       });
diff --git a/__tests__/src/components/SearchHit.test.js b/__tests__/src/components/SearchHit.test.js
index 3db42a226f4f1be2ba8646ee75ab9804a274f318..e999a8b1e8efe2fa83a0294167d76ce2d21d49ae 100644
--- a/__tests__/src/components/SearchHit.test.js
+++ b/__tests__/src/components/SearchHit.test.js
@@ -24,7 +24,6 @@ const Subject = (props) => (
     announcer={() => {}}
     annotation={{ targetId: 'x' }}
     annotationId="foo"
-    classes={{ windowSelected: 'windowSelected' }}
     hit={{
       after: ', and start the chainsaw',
       annotations: ['foo'],
@@ -46,7 +45,6 @@ describe('SearchHit', () => {
     render(<Subject selectAnnotation={selectAnnotation} />);
 
     expect(screen.getByRole('listitem')).toHaveClass('Mui-selected');
-    expect(screen.getByRole('listitem')).toHaveClass('windowSelected');
     expect(screen.getByRole('listitem')).toHaveTextContent('1Light up the moose , and start the chai more');
 
     await user.click(screen.getByRole('button'));
@@ -69,14 +67,13 @@ describe('SearchHit', () => {
     it('renders the annotationLabel if present', () => {
       render(<Subject annotationLabel="The Anno Label" />);
 
-      expect(screen.getAllByRole('heading', { level: 6 })).toHaveLength(2);
-      expect(screen.getByRole('heading', { level: 6, name: 'The Anno Label' })).toHaveClass('MuiTypography-subtitle2');
+      expect(screen.getByRole('heading', { level: 4, name: 'The Anno Label' })).toBeInTheDocument();
     });
 
     it('does not render the typography if no annotation label is present', () => {
       render(<Subject />);
 
-      expect(screen.getByRole('heading', { level: 6 })).toBeInTheDocument();
+      expect(screen.getByRole('heading', { level: 4 })).toBeInTheDocument();
     });
   });
 
diff --git a/__tests__/src/components/SearchPanel.test.js b/__tests__/src/components/SearchPanel.test.js
index 8b4fb3a304ea83af9f521338171e3a1bdea74759..cd7b50ee01958a1ab2aff5109d3edd4e9b7ad274 100644
--- a/__tests__/src/components/SearchPanel.test.js
+++ b/__tests__/src/components/SearchPanel.test.js
@@ -54,7 +54,7 @@ describe('SearchPanel', () => {
   it('has the SearchPanelControls component', () => {
     createWrapper();
 
-    expect(screen.getByRole('textbox', { name: 'searchInputLabel' })).toBeInTheDocument();
+    expect(screen.getByRole('combobox', { name: 'searchInputLabel' })).toBeInTheDocument();
     expect(screen.getByRole('button', { name: 'searchSubmitAria' })).toBeInTheDocument();
   });
 
diff --git a/__tests__/src/components/SearchPanelControls.test.js b/__tests__/src/components/SearchPanelControls.test.js
index e2ab065c2730aafab356b1af114d26ca6e28513d..0b018912404980e4266fbf88a25092ac8f518e09 100644
--- a/__tests__/src/components/SearchPanelControls.test.js
+++ b/__tests__/src/components/SearchPanelControls.test.js
@@ -33,7 +33,7 @@ describe('SearchPanelControls', () => {
       searchService: { id: 'http://example.com/search', options: { resource: { id: 'abc' } } },
     });
 
-    await user.click(screen.getByRole('textbox'));
+    await user.click(screen.getByRole('combobox'));
     await user.keyboard('somestring');
     await user.click(await screen.findByText('somestring 12345'));
     expect(fetchSearch).toHaveBeenCalledWith('window', 'cw', 'http://example.com/search?q=somestring+12345', 'somestring 12345');
@@ -44,7 +44,7 @@ describe('SearchPanelControls', () => {
   it('renders a text input through the renderInput prop', () => {
     createWrapper();
 
-    expect(screen.getByRole('textbox')).toHaveAttribute('id', 'search-cw');
+    expect(screen.getByRole('combobox')).toHaveAttribute('id', 'search-cw');
   });
   it('endAdornment is a SearchIcon (with no CircularProgress indicator)', () => {
     createWrapper();
@@ -67,7 +67,7 @@ describe('SearchPanelControls', () => {
     };
     createWrapper({ fetchSearch, query: 'asdf', searchService });
 
-    await user.clear(screen.getByRole('textbox'));
+    await user.clear(screen.getByRole('combobox'));
     await user.keyboard('yolo');
     await user.click(screen.getByRole('button'));
 
@@ -84,7 +84,7 @@ describe('SearchPanelControls', () => {
 
     createWrapper({ fetchSearch, query: '', searchService });
 
-    await user.clear(screen.getByRole('textbox'));
+    await user.clear(screen.getByRole('combobox'));
     await user.click(screen.getByRole('button', { name: 'searchSubmitAria' }));
     expect(fetchSearch).not.toHaveBeenCalled();
   });
@@ -92,12 +92,12 @@ describe('SearchPanelControls', () => {
   describe('input', () => {
     it('has the query prop has the input value on intial render', () => {
       createWrapper({ query: 'Wolpertinger' });
-      expect(screen.getByRole('textbox')).toHaveValue('Wolpertinger');
+      expect(screen.getByRole('combobox')).toHaveValue('Wolpertinger');
     });
 
     it('clears the local search state/input when the incoming query prop has been cleared', () => {
       const wrapper = createWrapper({ query: 'Wolpertinger' });
-      expect(screen.getByRole('textbox')).toHaveValue('Wolpertinger');
+      expect(screen.getByRole('combobox')).toHaveValue('Wolpertinger');
 
       wrapper.rerender((
         <SearchPanelControls
@@ -107,7 +107,7 @@ describe('SearchPanelControls', () => {
         />
       ));
 
-      expect(screen.getByRole('textbox')).toHaveValue('');
+      expect(screen.getByRole('combobox')).toHaveValue('');
     });
   });
 });
diff --git a/__tests__/src/components/SearchResults.test.js b/__tests__/src/components/SearchResults.test.js
index 14a906cb6bf052c50fafea29a677a7f372039e35..3579a9789afeea5b5de2df963e75b981cfb92fb4 100644
--- a/__tests__/src/components/SearchResults.test.js
+++ b/__tests__/src/components/SearchResults.test.js
@@ -95,8 +95,8 @@ describe('SearchResults', () => {
         searchHits: [],
       });
 
-      expect(screen.getByRole('heading', { level: 6, name: 'The Anno Label' })).toBeInTheDocument();
-      expect(screen.getByRole('heading', { level: 6, name: 'Annother Anno Label' })).toBeInTheDocument();
+      expect(screen.getByRole('heading', { level: 4, name: 'The Anno Label' })).toBeInTheDocument();
+      expect(screen.getByRole('heading', { level: 4, name: 'Annother Anno Label' })).toBeInTheDocument();
     });
   });
 
diff --git a/__tests__/src/components/ThumbnailCanvasGrouping.test.js b/__tests__/src/components/ThumbnailCanvasGrouping.test.js
index 96895ba47f9f91d210fbb08f3a061669089405f9..8bfff1d6d06dc63f5b0ff8a348b4eb52c744e72d 100644
--- a/__tests__/src/components/ThumbnailCanvasGrouping.test.js
+++ b/__tests__/src/components/ThumbnailCanvasGrouping.test.js
@@ -36,12 +36,13 @@ describe('ThumbnailCanvasGrouping', () => {
     setCanvas = jest.fn();
     wrapper = createWrapper({ data, setCanvas });
   });
+  const spyCurrentCanvasClass = jest.spyOn(ThumbnailCanvasGrouping.prototype, 'currentCanvasClass');
+  afterEach(() => {
+    spyCurrentCanvasClass.mockClear();
+  });
   it('renders', () => {
     expect(screen.getByRole('gridcell')).toBeInTheDocument();
   });
-  it('sets a mirador-current-canvas-grouping class on current canvas', () => {
-    expect(screen.getByRole('button')).toHaveClass('mirador-current-canvas-grouping');
-  });
   it('renders a CaptionedIIIFThumbnail', () => {
     expect(screen.getByText('Image 1')).toBeInTheDocument();
   });
@@ -49,9 +50,9 @@ describe('ThumbnailCanvasGrouping', () => {
     wrapper.unmount();
     const user = userEvent.setup();
     wrapper = createWrapper({ data, index: 0, setCanvas });
-
     await user.click(wrapper.container.querySelector('.mirador-thumbnail-nav-canvas-0')); // eslint-disable-line testing-library/no-node-access
-
+    expect(spyCurrentCanvasClass).toHaveBeenCalledWith([0]);
+    expect(spyCurrentCanvasClass).toHaveReturnedWith('current-canvas-grouping');
     expect(setCanvas).toHaveBeenCalledWith('http://iiif.io/api/presentation/2.0/example/fixtures/canvas/24/c1.json');
   });
   describe('attributes based off far-bottom position', () => {
diff --git a/__tests__/src/components/WindowAuthenticationBar.test.js b/__tests__/src/components/WindowAuthenticationBar.test.js
index b47771b1d06e105ceb32e335cae3ce96d8038a57..c4368b81132bfd1c1202473d4fc296444eb73404 100644
--- a/__tests__/src/components/WindowAuthenticationBar.test.js
+++ b/__tests__/src/components/WindowAuthenticationBar.test.js
@@ -37,38 +37,36 @@ describe('AuthenticationControl', () => {
   it('renders a non-collapsing version if there is no description', () => {
     createWrapper({ description: undefined, header: undefined });
     expect(screen.getByText('Log in to see more', { selector: 'span' })).toBeInTheDocument();
-    expect(screen.getByText('Login', { selector: 'span' })).toBeInTheDocument();
+    expect(screen.getByRole('button')).toHaveTextContent('Login');
   });
 
   it('renders a collapsable version if there is a description', async () => {
     createWrapper({ description: 'long description', header: 'Login to Example Institution' });
     const continueBtn = document.querySelectorAll('.MuiButtonBase-root')[0];
-    const cancelBtn = screen.getByText('cancel', { selector: 'span' }).closest('button');
-    const loginBtn = screen.getByText('Login', { selector: 'span' });
     const collapseEl = document.querySelector('.MuiCollapse-hidden');
 
     // disable transition animations for easier testing of the Mui Collapse open/close state
     config.disabled = true;
     // initial collapsed state: Presence of continue button text. Hidden cancelBtn, loginBtn, and description
     expect(screen.getByText('continue')).toBeInTheDocument();
-    expect(cancelBtn).not.toBeVisible();
-    expect(loginBtn).not.toBeVisible();
+    expect(screen.queryByRole('button', { name: 'cancel' })).not.toBeInTheDocument();
+    expect(screen.queryByRole('button', { name: 'Login' })).not.toBeInTheDocument();
     expect(within(collapseEl).getByText('long description')).not.toBeVisible();
     // click to expand
     await user.click(continueBtn);
     // expanded state: Removal of continue button text from DOM. Visible cancelBtn, loginBtn, and description
     expect(screen.queryByText('continue')).not.toBeInTheDocument();
-    expect(cancelBtn).toBeVisible();
-    expect(loginBtn).toBeVisible();
+    expect(screen.getByRole('button', { name: 'cancel' })).toBeVisible();
+    expect(screen.getByRole('button', { name: 'Login' })).toBeVisible();
     expect(within(collapseEl).getByText('long description')).toBeVisible();
     expect(collapseEl).toHaveClass('MuiCollapse-entered');
 
     // click the cancel button to collapse
-    await user.click(cancelBtn);
+    await user.click(screen.getByRole('button', { name: 'cancel' }));
     // collapsed state: Presence of continue button text. Hidden cancelBtn, loginBtn, and description
     expect(screen.getByText('continue')).toBeInTheDocument();
-    expect(cancelBtn).not.toBeVisible();
-    expect(loginBtn).not.toBeVisible();
+    expect(screen.queryByRole('button', { name: 'cancel' })).not.toBeInTheDocument();
+    expect(screen.queryByRole('button', { name: 'Login' })).not.toBeInTheDocument();
     expect(within(collapseEl).getByText('long description')).not.toBeVisible();
     // re-enable transition animation
     config.disabled = false;
@@ -77,7 +75,7 @@ describe('AuthenticationControl', () => {
   it('triggers an action when the confirm button is clicked', async () => {
     const onConfirm = jest.fn();
     createWrapper({ onConfirm });
-    await user.click(screen.getByText('Login', { selector: 'span' }).closest('button'));
+    await user.click(screen.getByRole('button', { name: 'Login' }));
     expect(onConfirm).toHaveBeenCalled();
   });
 
diff --git a/__tests__/src/components/WindowCanvasNavigationControls.test.js b/__tests__/src/components/WindowCanvasNavigationControls.test.js
index d089de29157852f4bd77cb0d56e582cac1145b7f..de08147cc359a800fcaae3b5f26e54b996c67af1 100644
--- a/__tests__/src/components/WindowCanvasNavigationControls.test.js
+++ b/__tests__/src/components/WindowCanvasNavigationControls.test.js
@@ -28,7 +28,7 @@ describe('WindowCanvasNavigationControls', () => {
 
   it('renders only a screen-reader accessibile version when visible=false', () => {
     const { container } = render(<Subject visible={false} />);
-    expect(container.firstChild.classList[1]).toMatch(/srOnly/); // eslint-disable-line testing-library/no-node-access
+    expect(container.firstChild).toHaveStyle({ height: '1px', margin: '-1px', width: '1px' }); // eslint-disable-line testing-library/no-node-access
   });
 
   it('stacks the nav controls on small width screens', () => {
@@ -37,10 +37,7 @@ describe('WindowCanvasNavigationControls', () => {
   });
 
   it('shows the zoom control component when specified', () => {
-    render(
-      <Subject />,
-      { preloadedState: { workspace: { showZoomControls: true } } },
-    );
+    render(<Subject showZoomControls />);
     expect(screen.getByRole('button', { name: 'zoomIn' })).toBeInTheDocument();
     expect(screen.getByRole('button', { name: 'zoomOut' })).toBeInTheDocument();
     expect(screen.getByRole('button', { name: 'zoomReset' })).toBeInTheDocument();
diff --git a/__tests__/src/components/WindowSideBar.test.js b/__tests__/src/components/WindowSideBar.test.js
index 895e20fb3516246cd1e681630d9733af96dc8133..0fa75243cf9bb7be907346cdfc7bdd06db3ffd20 100644
--- a/__tests__/src/components/WindowSideBar.test.js
+++ b/__tests__/src/components/WindowSideBar.test.js
@@ -5,7 +5,6 @@ import { WindowSideBar } from '../../../src/components/WindowSideBar';
 function createWrapper({ ...props }) {
   return render(
     <WindowSideBar
-      classes={{ drawer: 'test-drawer' }}
       t={k => k}
       windowId="xyz"
       {...props}
@@ -26,7 +25,6 @@ function createWrapper({ ...props }) {
 describe('WindowSideBar when closed', () => {
   it('renders without an error', () => {
     createWrapper({});
-    expect(document.querySelector('.test-drawer')).toBeInTheDocument(); // eslint-disable-line testing-library/no-node-access
     expect(screen.queryByRole('navigation', { accessibleName: 'sidebarPanelsNavigation' })).not.toBeInTheDocument();
   });
 });
diff --git a/__tests__/src/components/WindowSideBarCanvasPanel.test.js b/__tests__/src/components/WindowSideBarCanvasPanel.test.js
index 9ad3ce6cca69634ab1cc5015e595680a894fb1bf..9c3c48ca0ac8ebef6279fba2c6ba317018967054 100644
--- a/__tests__/src/components/WindowSideBarCanvasPanel.test.js
+++ b/__tests__/src/components/WindowSideBarCanvasPanel.test.js
@@ -65,7 +65,7 @@ describe('WindowSideBarCanvasPanel', () => {
     createWrapper({ multipleSequences: true, updateSequence });
 
     expect(screen.getByTestId('sequence-select')).toHaveTextContent('a');
-    await user.click(within(screen.getByTestId('sequence-select')).getByRole('button'));
+    await user.click(within(screen.getByTestId('sequence-select')).getByRole('combobox'));
 
     const listbox = within(screen.getByRole('listbox'));
     expect(listbox.getAllByRole('option')).toHaveLength(2);
diff --git a/__tests__/src/components/WindowTopMenuButton.test.js b/__tests__/src/components/WindowTopMenuButton.test.js
index 86ef9584d47c462e9db7ba0f522c36f3e8ea7013..15d4b65f42d325a951427a68d261e999aba4f1dd 100644
--- a/__tests__/src/components/WindowTopMenuButton.test.js
+++ b/__tests__/src/components/WindowTopMenuButton.test.js
@@ -38,9 +38,16 @@ describe('WindowTopMenuButton', () => {
     expect(screen.queryByRole('menu')).not.toBeInTheDocument();
   });
 
-  it('the button has a class indicating that it is "selected" once it is clicked', async () => {
+  it('the open attribute of the button is null without being clicked', async () => {
+    render(<Subject />);
+    // without a click, the button is not open and therefore doesn't have aria-owns attr
+    expect(screen.getByLabelText('windowMenu')).not.toHaveAttribute('aria-owns'); // eslint-disable-line testing-library/no-node-access
+  });
+
+  it('the open attribute of the button is applied once it is clicked', async () => {
     render(<Subject />);
     await user.click(screen.getByLabelText('windowMenu'));
-    expect(screen.getByLabelText('windowMenu')).toHaveClass('ctrlBtnSelected'); // eslint-disable-line testing-library/no-node-access
+    // when 'open' is true, aria-owns is set to the id of the window
+    expect(screen.getByLabelText('windowMenu')).toHaveAttribute('aria-owns', 'window-menu_xyz'); // eslint-disable-line testing-library/no-node-access
   });
 });
diff --git a/__tests__/src/components/Workspace.test.js b/__tests__/src/components/Workspace.test.js
index 3f1fd853e79f7aec16a9fad1ab6b05b789675b1b..493598f751109c49936e69dd95271179c79dbbdb 100644
--- a/__tests__/src/components/Workspace.test.js
+++ b/__tests__/src/components/Workspace.test.js
@@ -83,22 +83,6 @@ describe('Workspace', () => {
     });
   });
 
-  describe('when the workspace control panel is displayed', () => {
-    it('has the *-with-control-panel class applied', () => {
-      const { container } = createWrapper();
-
-      expect(container.querySelector('.mirador-workspace-with-control-panel')).toBeInTheDocument();
-    });
-  });
-
-  describe('when the workspace control panel is not displayed', () => {
-    it('does not have the *-with-control-panel class applied', () => {
-      const { container } = createWrapper({ isWorkspaceControlPanelVisible: false });
-
-      expect(container.querySelector('.mirador-workspace-with-control-panel')).not.toBeInTheDocument();
-    });
-  });
-
   describe('drag and drop', () => {
     it('adds a new catalog entry from a manifest', async () => {
       const manifestJson = '{ "data": "123" }';
@@ -106,7 +90,7 @@ describe('Workspace', () => {
       const addWindow = jest.fn();
 
       const { container } = createWrapper({ addWindow });
-      const dropTarget = container.querySelector('.mirador-workspace-with-control-panel');
+      const dropTarget = container.querySelector('.mirador-workspace-viewport');
 
       const file = new File([manifestJson], 'manifest.json', { type: 'application/json' });
       const dataTransfer = {
@@ -129,7 +113,7 @@ describe('Workspace', () => {
 
       const { container } = createWrapper({ addWindow, allowNewWindows: false });
 
-      const dropTarget = container.querySelector('.mirador-workspace-with-control-panel');
+      const dropTarget = container.querySelector('.mirador-workspace-viewport');
 
       const file = new File([manifestJson], 'manifest.json', { type: 'application/json' });
       const dataTransfer = {
diff --git a/__tests__/src/components/WorkspaceElasticWindow.test.js b/__tests__/src/components/WorkspaceElasticWindow.test.js
index 5d8982ea6b553f3bafc7fa8ae0fb103ff307c8d5..03f565afd16baebc97bd1774e00dc388eb0273df 100644
--- a/__tests__/src/components/WorkspaceElasticWindow.test.js
+++ b/__tests__/src/components/WorkspaceElasticWindow.test.js
@@ -46,18 +46,13 @@ describe('WorkspaceElasticWindow', () => {
     expect(el).toHaveStyle({ height: '200px', transform: 'translate(5040px,5040px)', width: '200px' });
   });
   describe('focuses the window', () => {
-    it('adds class to focused window', () => {
-      const { container } = createWrapper({ classes: { focused: 'focused-window' }, focused: true, layout });
-      const el = container.firstChild;
-
-      expect(el).toHaveClass('focused-window');
-    });
     it('calls focusWindow when clicked', async () => {
       const user = userEvent.setup();
       const mockFocusWindow = jest.fn();
       const { container } = createWrapper({ focusWindow: mockFocusWindow, layout });
-      const el = container.querySelector('.mirador-window-top-bar');
-      await user.click(el);
+      const topBar = container.querySelector('.mirador-window-top-bar');
+      await user.click(topBar);
+
       expect(mockFocusWindow).toHaveBeenCalled();
     });
   });
diff --git a/__tests__/src/components/ZoomControls.test.js b/__tests__/src/components/ZoomControls.test.js
index 6f7be5e3ad62133eec3c26a4b1ddadb9eda7dfbe..41a562513eb8b5d87d6765b003ebbc9771046786 100644
--- a/__tests__/src/components/ZoomControls.test.js
+++ b/__tests__/src/components/ZoomControls.test.js
@@ -6,74 +6,47 @@ import { ZoomControls } from '../../../src/components/ZoomControls';
 function createWrapper(props) {
   return render(
     <ZoomControls
-      classes={{ divider: 'divider', zoom_controls: 'zoom_controls' }}
       windowId="xyz"
       zoomToWorld={() => {}}
       {...props}
-
     />,
   );
 }
 
 describe('ZoomControls', () => {
   const viewer = { x: 100, y: 100, zoom: 1 };
-  const showZoomControls = false;
   let updateViewport;
 
-  describe('with showZoomControls=false', () => {
-    it('renders nothing unless asked', () => {
-      const { container } = createWrapper({ showZoomControls, updateViewport, viewer });
-      expect(container).toBeEmptyDOMElement();
+  const zoomToWorld = jest.fn();
+  let user;
+  beforeEach(() => {
+    user = userEvent.setup();
+    updateViewport = jest.fn();
+    createWrapper({
+      updateViewport, viewer, zoomToWorld,
     });
   });
 
-  describe('with showZoomControls=true', () => {
-    const zoomToWorld = jest.fn();
-    let user;
-    beforeEach(() => {
-      user = userEvent.setup();
-      updateViewport = jest.fn();
-      createWrapper({
-        showZoomControls: true, updateViewport, viewer, zoomToWorld,
-      });
-    });
-
-    it('renders a couple buttons', () => {
-      expect(screen.getByRole('button', { name: 'zoomIn' })).toBeInTheDocument();
-      expect(screen.getByRole('button', { name: 'zoomOut' })).toBeInTheDocument();
-      expect(screen.getByRole('button', { name: 'zoomReset' })).toBeInTheDocument();
-    });
-
-    it('has a zoom-in button', async () => {
-      await user.click(screen.getByRole('button', { name: 'zoomIn' }));
-
-      expect(updateViewport).toHaveBeenCalledWith('xyz', { zoom: 2 });
-    });
-
-    it('has a zoom-out button', async () => {
-      await user.click(screen.getByRole('button', { name: 'zoomOut' }));
-      expect(updateViewport).toHaveBeenCalledWith('xyz', { zoom: 0.5 });
-    });
+  it('renders a couple buttons', () => {
+    expect(screen.getByRole('button', { name: 'zoomIn' })).toBeInTheDocument();
+    expect(screen.getByRole('button', { name: 'zoomOut' })).toBeInTheDocument();
+    expect(screen.getByRole('button', { name: 'zoomReset' })).toBeInTheDocument();
+  });
 
-    it('has a zoom reset button', async () => {
-      await user.click(screen.getByRole('button', { name: 'zoomReset' }));
+  it('has a zoom-in button', async () => {
+    await user.click(screen.getByRole('button', { name: 'zoomIn' }));
 
-      expect(zoomToWorld).toHaveBeenCalledWith(false);
-    });
+    expect(updateViewport).toHaveBeenCalledWith('xyz', { zoom: 2 });
   });
 
-  /* eslint-disable testing-library/no-container, testing-library/no-node-access */
-  describe('responsive divider', () => {
-    it('is present when the displayDivider prop is true (default)', () => {
-      const { container } = createWrapper({ showZoomControls: true, viewer });
-
-      expect(container.querySelector('.divider')).toBeInTheDocument();
-    });
+  it('has a zoom-out button', async () => {
+    await user.click(screen.getByRole('button', { name: 'zoomOut' }));
+    expect(updateViewport).toHaveBeenCalledWith('xyz', { zoom: 0.5 });
+  });
 
-    it('is not present when the displayDivider prop is false', () => {
-      const { container } = createWrapper({ displayDivider: false, showZoomControls: true, viewer });
+  it('has a zoom reset button', async () => {
+    await user.click(screen.getByRole('button', { name: 'zoomReset' }));
 
-      expect(container.querySelector('.divider')).not.toBeInTheDocument();
-    });
+    expect(zoomToWorld).toHaveBeenCalledWith(false);
   });
 });
diff --git a/__tests__/utils/test-utils.js b/__tests__/utils/test-utils.js
index 7bc1adf23faae99a0d9146a63145f7947dea6088..7104dec6b038df0a91a8744b5378e22aeab848e9 100644
--- a/__tests__/utils/test-utils.js
+++ b/__tests__/utils/test-utils.js
@@ -3,9 +3,12 @@ import { render } from '@testing-library/react';
 import PropTypes from 'prop-types';
 import { createStore, applyMiddleware } from 'redux';
 import thunkMiddleware from 'redux-thunk';
+import { createTheme, ThemeProvider } from '@mui/material/styles';
 import createRootReducer from '../../src/state/reducers/rootReducer';
+import settings from '../../src/config/settings';
 
 const rootReducer = createRootReducer();
+const theme = createTheme(settings.theme);
 
 /**
  * Hook up our rendered object to redux
@@ -21,7 +24,7 @@ function renderWithProviders(
 ) {
   /** :nodoc: */
   function Wrapper({ children }) {
-    return <Provider store={store}>{children}</Provider>;
+    return <ThemeProvider theme={theme}><Provider store={store}>{children}</Provider></ThemeProvider>;
   }
 
   Wrapper.propTypes = {
diff --git a/jest-puppeteer.config.js b/jest-puppeteer.config.js
index b7f3d29270c58ad2de562ff6eceb7c3ffa280179..31bf265ad41b8b662bbac4fa8cb0062e7652777a 100644
--- a/jest-puppeteer.config.js
+++ b/jest-puppeteer.config.js
@@ -1,6 +1,6 @@
 module.exports = {
   launch: {
-    headless: process.env.HEADLESS !== 'false',
+    headless: process.env.HEADLESS !== 'false' ? 'new' : false,
   },
   server: [{
     command: 'npm run server -- -p 4488',
diff --git a/jest.json b/jest.json
index b5713a9dc77afc15459a2b531716ba0d63c852f3..947d95cd44f04a7c4501be996ca01b82001e7832 100644
--- a/jest.json
+++ b/jest.json
@@ -33,7 +33,7 @@
       "<rootDir>/__tests__/utils"
     ],
     "preset": "jest-puppeteer",
-    "setupFilesAfterEnv": ["@testing-library/jest-dom/extend-expect"],
+    "setupFilesAfterEnv": ["@testing-library/jest-dom/jest-globals"],
     "transformIgnorePatterns": [
       "<rootDir>/node_modules/(?!@react-dnd|react-dnd|dnd-core|react-dnd-html5-backend|dnd-multi-backend|rdndmb-html5-to-touch)"
     ],
@@ -58,7 +58,7 @@
     "preset": "jest-puppeteer",
     "setupFilesAfterEnv": [
       "<rootDir>/setupJestIntegration.js",
-      "@testing-library/jest-dom/extend-expect"
+      "@testing-library/jest-dom/jest-globals"
     ],
     "transformIgnorePatterns": [
       "<rootDir>/node_modules/(?!@react-dnd|react-dnd|dnd-core|react-dnd-html5-backend|dnd-multi-backend|rdndmb-html5-to-touch)"
diff --git a/package.json b/package.json
index 567470b7f75eb603e8af7c4f6618dd03b1a7608e..d77b1f238acfc073e66039b66cadfc3bbf861a69 100644
--- a/package.json
+++ b/package.json
@@ -33,18 +33,21 @@
   ],
   "repository": "https://github.com/ProjectMirador/mirador",
   "dependencies": {
+    "@emotion/cache": "^11.11.0",
+    "@emotion/react": "^11.10.6",
+    "@emotion/styled": "^11.10.6",
     "@hello-pangea/dnd": "^16.0.1",
-    "@material-ui/core": "^4.12.3",
-    "@material-ui/icons": "^4.9.1",
-    "@material-ui/lab": "^4.0.0-alpha.53",
+    "@mui/icons-material": "^5.11.16",
+    "@mui/lab": "^5.0.0-alpha.134",
+    "@mui/material": "^5.13.5",
+    "@mui/utils": "^5.13.1",
+    "@mui/x-tree-view": "^6.17.0",
     "@react-aria/live-announcer": "^3.1.2",
+    "@redux-devtools/extension": "^3.3.0",
     "classnames": "^2.2.6",
-    "clsx": "^1.0.4",
     "deepmerge": "^4.2.2",
     "dompurify": "^3.0.0",
-    "i18next": "^21.0.0 || ^22.0.0",
-    "jss": "^10.3.0",
-    "jss-rtl": "^0.3.0",
+    "i18next": "^21.0.0 || ^22.0.0 || ^23.0.0",
     "lodash": "^4.17.11",
     "manifesto.js": "^4.2.0",
     "normalize-url": "^4.5.0",
@@ -58,7 +61,7 @@
     "react-dnd-multi-backend": "^8.0.0",
     "react-dnd-touch-backend": "^16.0.0",
     "react-full-screen": "^1.1.1",
-    "react-i18next": "^11.7.0 || ^12.0.0",
+    "react-i18next": "^11.7.0 || ^12.0.0 || ^13.0.0",
     "react-image": "^4.0.1",
     "react-intersection-observer": "^9.0.0",
     "react-mosaic-component": "^6.0.0",
@@ -73,6 +76,8 @@
     "redux-saga": "^1.1.3",
     "redux-thunk": "^2.3.0",
     "reselect": "^4.0.0",
+    "stylis": "^4.3.0",
+    "stylis-plugin-rtl": "^2.1.1",
     "url": "^0.11.0",
     "uuid": "^8.1.0 || ^9.0.0"
   },
@@ -88,7 +93,7 @@
     "@babel/preset-react": "^7.16.7",
     "@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
     "@testing-library/dom": "^9.2.0",
-    "@testing-library/jest-dom": "^5.16.5",
+    "@testing-library/jest-dom": "^6.1.5",
     "@testing-library/react": "^12.1.5",
     "@testing-library/user-event": "^14.4.3",
     "@typescript-eslint/eslint-plugin": "^5.15.0",
@@ -108,19 +113,19 @@
     "eslint-plugin-flowtype": "^8.0.3",
     "eslint-plugin-import": "^2.25.4",
     "eslint-plugin-jest": "^27.1.5",
-    "eslint-plugin-jest-dom": "^4.0.3",
+    "eslint-plugin-jest-dom": "^5.1.0",
     "eslint-plugin-jsx-a11y": "^6.4.1",
     "eslint-plugin-react": "^7.29.4",
     "eslint-plugin-react-hooks": "^4.6.0",
     "eslint-plugin-testing-library": "^5.10.2",
-    "glob": "^9.3.0",
+    "glob": "^10.3.0",
     "http-server": "^14.1.0",
     "jest": "^29.3.1",
     "jest-environment-jsdom": "^29.4.3",
     "jest-fetch-mock": "^3.0.0",
-    "jest-puppeteer": "^8.0.0",
-    "jsdom": "^21.0.0",
-    "puppeteer": "^19.0.0",
+    "jest-puppeteer": "^9.0.2",
+    "jsdom": "^23.0.0",
+    "puppeteer": "^21.0.0",
     "react": "^17.0.0",
     "react-dnd-test-backend": "^16.0.1",
     "react-dom": "^17.0.0",
diff --git a/src/components/AnnotationSettings.js b/src/components/AnnotationSettings.js
index dd91bdc754f4ef9f4494d62a1f43ce64593af6dd..f6fec27ad711fa018e2ce39177c5d302c31c2e5a 100644
--- a/src/components/AnnotationSettings.js
+++ b/src/components/AnnotationSettings.js
@@ -1,7 +1,7 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import VisibilityIcon from '@material-ui/icons/VisibilitySharp';
-import VisibilityOffIcon from '@material-ui/icons/VisibilityOffSharp';
+import VisibilityIcon from '@mui/icons-material/VisibilitySharp';
+import VisibilityOffIcon from '@mui/icons-material/VisibilityOffSharp';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 
 /**
diff --git a/src/components/AppProviders.js b/src/components/AppProviders.js
index e4bcddeac7af38bf14d8c537da32fcbc9717119f..f39aae60984e174a60d8a569b591bc78b6275753 100644
--- a/src/components/AppProviders.js
+++ b/src/components/AppProviders.js
@@ -3,13 +3,15 @@ import PropTypes from 'prop-types';
 import { FullScreen, useFullScreenHandle } from 'react-full-screen';
 import { I18nextProvider } from 'react-i18next';
 import {
-  ThemeProvider, StylesProvider, createTheme, jssPreset, createGenerateClassName,
-} from '@material-ui/core/styles';
+  ThemeProvider, StyledEngineProvider, createTheme,
+} from '@mui/material/styles';
 import { DndContext, DndProvider } from 'react-dnd';
 import { MultiBackend } from 'react-dnd-multi-backend';
 import { HTML5toTouch } from 'rdndmb-html5-to-touch';
-import { create } from 'jss';
-import rtl from 'jss-rtl';
+import rtlPlugin from 'stylis-plugin-rtl';
+import { prefixer } from 'stylis';
+import { CacheProvider } from '@emotion/react';
+import createCache from '@emotion/cache';
 import createI18nInstance from '../i18n';
 import FullScreenContext from '../contexts/FullScreenContext';
 
@@ -92,12 +94,25 @@ export class AppProviders extends Component {
   /** */
   render() {
     const {
-      children, createGenerateClassNameOptions,
+      children,
       theme, translations,
       dndManager,
     } = this.props;
 
-    const generateClassName = createGenerateClassName(createGenerateClassNameOptions);
+    /**
+     * Create rtl emotion cache
+     */
+    const cacheRtl = createCache({
+      key: 'muirtl',
+      stylisPlugins: [prefixer, rtlPlugin],
+    });
+
+    /**
+     * Create default emotion cache
+     */
+    const cacheDefault = createCache({
+      key: 'mui',
+    });
 
     Object.keys(translations).forEach((lng) => {
       this.i18n.addResourceBundle(lng, 'translation', translations[lng], true, true);
@@ -106,18 +121,15 @@ export class AppProviders extends Component {
     return (
       <FullScreenShim>
         <I18nextProvider i18n={this.i18n}>
-          <ThemeProvider
-            theme={createTheme(theme)}
-          >
-            <StylesProvider
-              jss={create({ plugins: [...jssPreset().plugins, rtl()] })}
-              generateClassName={generateClassName}
-            >
-              <MaybeDndProvider dndManager={dndManager}>
-                {children}
-              </MaybeDndProvider>
-            </StylesProvider>
-          </ThemeProvider>
+          <StyledEngineProvider injectFirst>
+            <CacheProvider value={theme.direction === 'rtl' ? cacheRtl : cacheDefault}>
+              <ThemeProvider theme={createTheme((theme))}>
+                <MaybeDndProvider dndManager={dndManager}>
+                  {children}
+                </MaybeDndProvider>
+              </ThemeProvider>
+            </CacheProvider>
+          </StyledEngineProvider>
         </I18nextProvider>
       </FullScreenShim>
     );
@@ -126,7 +138,6 @@ export class AppProviders extends Component {
 
 AppProviders.propTypes = {
   children: PropTypes.node,
-  createGenerateClassNameOptions: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   dndManager: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   language: PropTypes.string.isRequired,
   theme: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
@@ -135,6 +146,5 @@ AppProviders.propTypes = {
 
 AppProviders.defaultProps = {
   children: null,
-  createGenerateClassNameOptions: {},
   dndManager: undefined,
 };
diff --git a/src/components/AttributionPanel.js b/src/components/AttributionPanel.js
index c2d8cc6979e1332c0b9ef46a4c0369209d645342..b1d9c6ebec7acf6af795a26c83c8e205d0df8e1d 100644
--- a/src/components/AttributionPanel.js
+++ b/src/components/AttributionPanel.js
@@ -1,14 +1,24 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
-import Link from '@material-ui/core/Link';
-import Skeleton from '@material-ui/lab/Skeleton';
+import { styled } from '@mui/material/styles';
+import Typography from '@mui/material/Typography';
+import Link from '@mui/material/Link';
+import Skeleton from '@mui/material/Skeleton';
 import { Img } from 'react-image';
 import CompanionWindow from '../containers/CompanionWindow';
+import { CompanionWindowSection } from './CompanionWindowSection';
 import { LabelValueMetadata } from './LabelValueMetadata';
 import ns from '../config/css-ns';
 import { PluginHook } from './PluginHook';
 
+const StyledLogo = styled(Img)(() => ({
+  maxWidth: '100%',
+}));
+
+const StyledPlaceholder = styled(Skeleton)(({ theme }) => ({
+  backgroundColor: theme.palette.grey[300],
+}));
+
 /**
  * WindowSideBarInfoPanel
  */
@@ -24,7 +34,6 @@ export class AttributionPanel extends Component {
       rights,
       windowId,
       id,
-      classes,
       t,
     } = this.props;
 
@@ -35,7 +44,7 @@ export class AttributionPanel extends Component {
         windowId={windowId}
         id={id}
       >
-        <div className={classes.section}>
+        <CompanionWindowSection>
           { requiredStatement && (
             <LabelValueMetadata labelValuePairs={requiredStatement} defaultLabel={t('attribution')} />
           )}
@@ -53,20 +62,19 @@ export class AttributionPanel extends Component {
               </dl>
             )
           }
-        </div>
+        </CompanionWindowSection>
 
         { manifestLogo && (
-          <div className={classes.section}>
-            <Img
+          <CompanionWindowSection>
+            <StyledLogo
               src={[manifestLogo]}
               alt=""
               role="presentation"
-              className={classes.logo}
               unloader={
-                <Skeleton className={classes.placeholder} variant="rect" height={60} width={60} />
+                <StyledPlaceholder variant="rectangular" height={60} width={60} />
               }
             />
-          </div>
+          </CompanionWindowSection>
         )}
 
         <PluginHook {...this.props} />
@@ -76,7 +84,6 @@ export class AttributionPanel extends Component {
 }
 
 AttributionPanel.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string),
   id: PropTypes.string.isRequired,
   manifestLogo: PropTypes.string,
   requiredStatement: PropTypes.arrayOf(PropTypes.shape({
@@ -89,7 +96,6 @@ AttributionPanel.propTypes = {
 };
 
 AttributionPanel.defaultProps = {
-  classes: {},
   manifestLogo: null,
   requiredStatement: null,
   rights: null,
diff --git a/src/components/AudioViewer.js b/src/components/AudioViewer.js
index ab7b9d6883b7186b6b990744707d5be5923eab32..9ceb07d78826542af7e9133df4c66f4ea42232a4 100644
--- a/src/components/AudioViewer.js
+++ b/src/components/AudioViewer.js
@@ -1,40 +1,48 @@
-import { Component, Fragment } from 'react';
+import { Fragment } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
+
+const StyledContainer = styled('div')({
+  alignItems: 'center',
+  display: 'flex',
+  width: '100%',
+});
+
+const StyledAudio = styled('audio')({
+  width: '100%',
+});
 
 /** */
-export class AudioViewer extends Component {
+export function AudioViewer(props) {
   /* eslint-disable jsx-a11y/media-has-caption */
   /** */
-  render() {
-    const {
-      captions, classes, audioOptions, audioResources,
-    } = this.props;
+  const {
+    captions, audioOptions, audioResources,
+  } = props;
 
-    return (
-      <div className={classes.container}>
-        <audio className={classes.audio} {...audioOptions}>
-          {audioResources.map(audio => (
-            <Fragment key={audio.id}>
-              <source src={audio.id} type={audio.getFormat()} />
-            </Fragment>
-          ))}
-          {captions.map(caption => (
-            <Fragment key={caption.id}>
-              <track src={caption.id} label={caption.getDefaultLabel()} srcLang={caption.getProperty('language')} />
-            </Fragment>
-          ))}
-        </audio>
-      </div>
-    );
-  }
-  /* eslint-enable jsx-a11y/media-has-caption */
+  return (
+    <StyledContainer>
+      <StyledAudio {...audioOptions}>
+        {audioResources.map((audio) => (
+          <Fragment key={audio.id}>
+            <source src={audio.id} type={audio.getFormat()} />
+          </Fragment>
+        ))}
+        {captions.map((caption) => (
+          <Fragment key={caption.id}>
+            <track src={caption.id} label={caption.getDefaultLabel()} srcLang={caption.getProperty('language')} />
+          </Fragment>
+        ))}
+      </StyledAudio>
+    </StyledContainer>
+  );
 }
+/* eslint-enable jsx-a11y/media-has-caption */
 
 AudioViewer.propTypes = {
   audioOptions: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   audioResources: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types
   captions: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
 };
 
 AudioViewer.defaultProps = {
diff --git a/src/components/Branding.js b/src/components/Branding.js
index d2f4d4f9e1a42cd605136baa9da81cba0526586e..9b3af649ccbb0520a5842e95778b45091a97205b 100644
--- a/src/components/Branding.js
+++ b/src/components/Branding.js
@@ -1,7 +1,8 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import IconButton from '@material-ui/core/IconButton';
-import Typography from '@material-ui/core/Typography';
+import IconButton from '@mui/material/IconButton';
+import Typography from '@mui/material/Typography';
+import Stack from '@mui/material/Stack';
 import MiradorIcon from './icons/MiradorIcon';
 
 /**
@@ -13,7 +14,7 @@ export class Branding extends Component {
     const { t, variant, ...ContainerProps } = this.props;
 
     return (
-      <div {...ContainerProps}>
+      <Stack alignItems="center" {...ContainerProps}>
         { variant === 'wide' && (
         <div>
           <Typography align="center" component="p" variant="h3">{t('mirador')}</Typography>
@@ -25,11 +26,12 @@ export class Branding extends Component {
             href="https://projectmirador.org"
             target="_blank"
             rel="noopener"
+            size="large"
           >
             <MiradorIcon aria-label={t('aboutMirador')} titleAccess={t('aboutMirador')} fontSize="large" />
           </IconButton>
         </Typography>
-      </div>
+      </Stack>
     );
   }
 }
diff --git a/src/components/CanvasAnnotations.js b/src/components/CanvasAnnotations.js
index 544e135d78469b3d2364dec08008cfdeeea14846..8b4993c3e28145bf4ed63fcd53e918cdc71b64b3 100644
--- a/src/components/CanvasAnnotations.js
+++ b/src/components/CanvasAnnotations.js
@@ -1,11 +1,10 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import clsx from 'clsx';
-import Chip from '@material-ui/core/Chip';
-import MenuList from '@material-ui/core/MenuList';
-import MenuItem from '@material-ui/core/MenuItem';
-import ListItemText from '@material-ui/core/ListItemText';
-import Typography from '@material-ui/core/Typography';
+import Chip from '@mui/material/Chip';
+import MenuList from '@mui/material/MenuList';
+import MenuItem from '@mui/material/MenuItem';
+import ListItemText from '@mui/material/ListItemText';
+import Typography from '@mui/material/Typography';
 import SanitizedHtml from '../containers/SanitizedHtml';
 import { ScrollTo } from './ScrollTo';
 
@@ -58,7 +57,7 @@ export class CanvasAnnotations extends Component {
   */
   render() {
     const {
-      annotations, classes, index, label, selectedAnnotationId, t, totalSize,
+      annotations, index, label, selectedAnnotationId, t, totalSize,
       listContainerComponent, htmlSanitizationRuleSet, hoveredAnnotationIds,
       containerRef,
     } = this.props;
@@ -66,53 +65,50 @@ export class CanvasAnnotations extends Component {
 
     return (
       <>
-        <Typography className={classes.sectionHeading} variant="overline">
+        <Typography sx={{ paddingLeft: 2, paddingRight: 1, paddingTop: 2 }} variant="overline">
           {t('annotationCanvasLabel', { context: `${index + 1}/${totalSize}`, label })}
         </Typography>
         <MenuList autoFocusItem variant="selectedMenu">
-          {
-            annotations.map(annotation => (
+          {annotations.map((annotation) => (
+            <ScrollTo
+              containerRef={containerRef}
+              key={`${annotation.id}-scroll`}
+              offsetTop={96} // offset for the height of the form above
+              scrollTo={selectedAnnotationId === annotation.id}
+              selected={selectedAnnotationId === annotation.id}
+            >
               <MenuItem
-                button
                 component={listContainerComponent}
-                className={clsx(
-                  classes.annotationListItem,
-                  {
-                    [classes.hovered]: hoveredAnnotationIds.includes(annotation.id),
+                variant="multiline"
+                divider
+                sx={{
+                  '&:hover,&:focus': {
+                    backgroundColor: 'action.hover',
                   },
-                )}
+                  backgroundColor: hoveredAnnotationIds.includes(annotation.id) ? 'action.hover' : '',
+                }}
                 key={annotation.id}
                 annotationid={annotation.id}
-                selected={selectedAnnotationId === annotation.id}
-                onClick={e => this.handleClick(e, annotation)}
+                onClick={(e) => this.handleClick(e, annotation)}
                 onFocus={() => this.handleAnnotationHover(annotation)}
                 onBlur={this.handleAnnotationBlur}
                 onMouseEnter={() => this.handleAnnotationHover(annotation)}
                 onMouseLeave={this.handleAnnotationBlur}
               >
-                <ScrollTo
-                  containerRef={containerRef}
-                  key={`${annotation.id}-scroll`}
-                  offsetTop={96} // offset for the height of the form above
-                  scrollTo={selectedAnnotationId === annotation.id}
-                >
-                  <ListItemText primaryTypographyProps={{ variant: 'body2' }}>
-                    <SanitizedHtml
-                      ruleSet={htmlSanitizationRuleSet}
-                      htmlString={annotation.content}
-                    />
-                    <div>
-                      {
-                        annotation.tags.map(tag => (
-                          <Chip size="small" variant="outlined" label={tag} id={tag} className={classes.chip} key={tag.toString()} />
-                        ))
-                      }
-                    </div>
-                  </ListItemText>
-                </ScrollTo>
+                <ListItemText
+                  primaryTypographyProps={{ variant: 'body2' }}
+                  primary={
+                    <SanitizedHtml ruleSet={htmlSanitizationRuleSet} htmlString={annotation.content} />
+                  }
+                  secondary={
+                    annotation.tags.map((tag) => (
+                      <Chip component="span" size="small" variant="outlined" label={tag} id={tag} key={tag.toString()} />
+                    ))
+                  }
+                />
               </MenuItem>
-            ))
-          }
+            </ScrollTo>
+          ))}
         </MenuList>
       </>
     );
@@ -126,7 +122,6 @@ CanvasAnnotations.propTypes = {
       id: PropTypes.string.isRequired,
     }),
   ),
-  classes: PropTypes.objectOf(PropTypes.string),
   containerRef: PropTypes.oneOfType([
     PropTypes.func,
     PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
@@ -146,7 +141,6 @@ CanvasAnnotations.propTypes = {
 };
 CanvasAnnotations.defaultProps = {
   annotations: [],
-  classes: {},
   containerRef: undefined,
   hoveredAnnotationIds: [],
   htmlSanitizationRuleSet: 'iiif',
diff --git a/src/components/CanvasInfo.js b/src/components/CanvasInfo.js
index 93f4b31243d6b9e5b33632085d6b53c4b3e3207c..39ec1a03fd29aeb92d23f60e2be2d672427bac5b 100644
--- a/src/components/CanvasInfo.js
+++ b/src/components/CanvasInfo.js
@@ -1,6 +1,6 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
+import Typography from '@mui/material/Typography';
 import CollapsibleSection from '../containers/CollapsibleSection';
 import SanitizedHtml from '../containers/SanitizedHtml';
 import { LabelValueMetadata } from './LabelValueMetadata';
diff --git a/src/components/CanvasLayers.js b/src/components/CanvasLayers.js
index 99e400ca2573b8237ef3137fa27712764c9b6d81..87f78490043e3700c25a0572f61f996372b18e7e 100644
--- a/src/components/CanvasLayers.js
+++ b/src/components/CanvasLayers.js
@@ -1,23 +1,36 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import clsx from 'clsx';
+import { styled } from '@mui/material/styles';
 import { v4 as uuid } from 'uuid';
-import Input from '@material-ui/core/Input';
-import InputAdornment from '@material-ui/core/InputAdornment';
-import List from '@material-ui/core/List';
-import ListItem from '@material-ui/core/ListItem';
-import Slider from '@material-ui/core/Slider';
-import Tooltip from '@material-ui/core/Tooltip';
-import DragHandleIcon from '@material-ui/icons/DragHandleSharp';
-import MoveToTopIcon from '@material-ui/icons/VerticalAlignTopSharp';
-import VisibilityIcon from '@material-ui/icons/VisibilitySharp';
-import VisibilityOffIcon from '@material-ui/icons/VisibilityOffSharp';
-import OpacityIcon from '@material-ui/icons/OpacitySharp';
-import Typography from '@material-ui/core/Typography';
+import Input from '@mui/material/Input';
+import InputAdornment from '@mui/material/InputAdornment';
+import List from '@mui/material/List';
+import ListItem from '@mui/material/ListItem';
+import Slider from '@mui/material/Slider';
+import Tooltip from '@mui/material/Tooltip';
+import DragHandleIcon from '@mui/icons-material/DragHandleSharp';
+import MoveToTopIcon from '@mui/icons-material/VerticalAlignTopSharp';
+import VisibilityIcon from '@mui/icons-material/VisibilitySharp';
+import VisibilityOffIcon from '@mui/icons-material/VisibilityOffSharp';
+import OpacityIcon from '@mui/icons-material/OpacitySharp';
+import Typography from '@mui/material/Typography';
 import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 import IIIFThumbnail from '../containers/IIIFThumbnail';
 
+const StyledDragHandle = styled('div')(({ theme }) => ({
+  alignItems: 'center',
+  borderRight: `0.5px solid ${theme.palette.divider}`,
+  display: 'flex',
+  flex: 1,
+  flexDirection: 'row',
+  marginBottom: theme.spacing(-2),
+  marginRight: theme.spacing(1),
+  marginTop: theme.spacing(-2),
+  maxWidth: theme.spacing(3),
+  width: theme.spacing(3),
+}));
+
 /** */
 const reorder = (list, startIndex, endIndex) => {
   const result = Array.from(list);
@@ -116,7 +129,6 @@ export class CanvasLayers extends Component {
   /** @private */
   renderLayer(resource, index) {
     const {
-      classes,
       layerMetadata,
       t,
     } = this.props;
@@ -136,10 +148,12 @@ export class CanvasLayers extends Component {
             maxHeight={height}
             maxWidth={width}
             resource={resource}
-            classes={{ image: classes.image, root: classes.thumbnail }}
+            border
           />
           <Typography
-            className={classes.label}
+            sx={{
+              paddingLeft: 1,
+            }}
             component="div"
             variant="body1"
           >
@@ -158,10 +172,21 @@ export class CanvasLayers extends Component {
         </div>
         <div style={{ alignItems: 'center', display: 'flex' }}>
           <Tooltip title={t('layer_opacity')}>
-            <OpacityIcon className={classes.opacityIcon} color={layer.visibility ? 'inherit' : 'disabled'} fontSize="small" />
+            <OpacityIcon sx={{ marginRight: 0.5 }} color={layer.visibility ? 'inherit' : 'disabled'} fontSize="small" />
           </Tooltip>
           <Input
-            classes={{ input: classes.opacityInput }}
+            sx={{
+              'MuiInput-input': {
+                '&::-webkit-outer-spin-button,&::-webkit-inner-spin-button': {
+                  margin: 0,
+                  WebkitAppearance: 'none',
+                },
+                MozAppearance: 'textfield',
+                textAlign: 'right',
+                typography: 'caption',
+                width: '3ch',
+              },
+            }}
             disabled={!layer.visibility}
             value={Math.round(layer.opacity * 100)}
             type="number"
@@ -174,7 +199,11 @@ export class CanvasLayers extends Component {
             }}
           />
           <Slider
-            className={classes.slider}
+            sx={{
+              marginLeft: 2,
+              marginRight: 2,
+              maxWidth: 150,
+            }}
             disabled={!layer.visibility}
             value={layer.opacity * 100}
             onChange={(e, value) => this.handleOpacityChange(resource.id, value)}
@@ -187,7 +216,6 @@ export class CanvasLayers extends Component {
   /** @private */
   renderDraggableLayer(resource, index) {
     const {
-      classes,
       t,
     } = this.props;
 
@@ -198,20 +226,33 @@ export class CanvasLayers extends Component {
             ref={provided.innerRef}
             {...provided.draggableProps}
             component="li"
-            className={clsx(
-              classes.listItem,
-              {
-                [classes.dragging]: snapshot.isDragging,
-              },
-            )}
+            divider
+            sx={{
+              alignItems: 'stretch',
+              cursor: 'pointer',
+              paddingBottom: 2,
+              paddingRight: 2,
+              paddingTop: 2,
+              ...(snapshot.isDragging && {
+                backgroundColor: 'action.hover',
+              }),
+            }}
             disableGutters
             key={resource.id}
           >
-            <div {...provided.dragHandleProps} className={classes.dragHandle}>
+            <StyledDragHandle
+              {...provided.dragHandleProps}
+              sx={{
+                '&:hover': {
+                  backgroundColor: snapshot.isDragging ? 'action.selected' : 'action.hover',
+                },
+                backgroundColor: snapshot.isDragging ? 'action.selected' : 'shades.light',
+              }}
+            >
               <Tooltip title={t('layer_move')}>
                 <DragHandleIcon />
               </Tooltip>
-            </div>
+            </StyledDragHandle>
             {this.renderLayer(resource, index)}
           </ListItem>
         )}
@@ -222,7 +263,6 @@ export class CanvasLayers extends Component {
   /** */
   render() {
     const {
-      classes,
       index,
       label,
       layers,
@@ -233,7 +273,14 @@ export class CanvasLayers extends Component {
     return (
       <>
         { totalSize > 1 && (
-          <Typography className={classes.sectionHeading} variant="overline">
+          <Typography
+            sx={{
+              paddingLeft: 1,
+              paddingRight: 1,
+              paddingTop: 2,
+            }}
+            variant="overline"
+          >
             {t('annotationCanvasLabel', { context: `${index + 1}/${totalSize}`, label })}
           </Typography>
         )}
@@ -241,7 +288,9 @@ export class CanvasLayers extends Component {
           <Droppable droppableId={this.droppableId}>
             {(provided, snapshot) => (
               <List
-                className={classes.list}
+                sx={{
+                  paddingTop: 0,
+                }}
                 {...provided.droppableProps}
                 ref={provided.innerRef}
               >
@@ -262,7 +311,6 @@ export class CanvasLayers extends Component {
 
 CanvasLayers.propTypes = {
   canvasId: PropTypes.string.isRequired,
-  classes: PropTypes.objectOf(PropTypes.string),
   index: PropTypes.number.isRequired,
   label: PropTypes.string.isRequired,
   layerMetadata: PropTypes.objectOf(PropTypes.shape({
@@ -277,6 +325,5 @@ CanvasLayers.propTypes = {
 };
 
 CanvasLayers.defaultProps = {
-  classes: {},
   layerMetadata: undefined,
 };
diff --git a/src/components/ChangeThemeDialog.js b/src/components/ChangeThemeDialog.js
index 146071b855d6dc492722e5ebec2c9d8dc9da2d7a..17bd83171aab087aa3eafd88173a167674f1a3fa 100644
--- a/src/components/ChangeThemeDialog.js
+++ b/src/components/ChangeThemeDialog.js
@@ -1,16 +1,20 @@
 import { Component } from 'react';
 import {
-  Dialog,
   DialogTitle,
   ListItemIcon,
   ListItemText,
   MenuList,
   MenuItem,
-  Typography,
   DialogContent,
-} from '@material-ui/core';
-import PaletteIcon from '@material-ui/icons/PaletteSharp';
+} from '@mui/material';
+import PaletteIcon from '@mui/icons-material/PaletteSharp';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
+import { WorkspaceDialog } from './WorkspaceDialog';
+
+const ThemeIcon = styled(PaletteIcon, { name: 'ThemeIcon', slot: 'icon' })(({ theme }) => ({
+  color: '#BDBDBD',
+}));
 
 /**
  * a simple dialog providing the possibility to switch the theme
@@ -36,7 +40,6 @@ export class ChangeThemeDialog extends Component {
   /** */
   render() {
     const {
-      classes,
       handleClose,
       open,
       selectedTheme,
@@ -44,42 +47,34 @@ export class ChangeThemeDialog extends Component {
       themeIds,
     } = this.props;
     return (
-      <Dialog
-        onClose={handleClose}
-        open={open}
-      >
-        <DialogTitle disableTypography>
-          <Typography variant="h2">
-            {t('changeTheme')}
-          </Typography>
+      <WorkspaceDialog onClose={handleClose} open={open} variant="menu">
+        <DialogTitle>
+          {t('changeTheme')}
         </DialogTitle>
-        <DialogContent className={classes.dialogContent}>
+        <DialogContent>
           <MenuList autoFocusItem>
-            {
-              themeIds.map(value => (
-                <MenuItem
-                  key={value}
-                  className={classes.listitem}
-                  onClick={() => { this.handleThemeChange(value); }}
-                  selected={value === selectedTheme}
-                  value={value}
-                >
-                  <ListItemIcon>
-                    <PaletteIcon className={classes[value]} />
-                  </ListItemIcon>
-                  <ListItemText>{t(value)}</ListItemText>
-                </MenuItem>
-              ))
-            }
+            {themeIds.map((value) => (
+              <MenuItem
+                key={value}
+                className="listitem"
+                onClick={() => this.handleThemeChange(value)}
+                selected={value === selectedTheme}
+                value={value}
+              >
+                <ListItemIcon>
+                  <ThemeIcon ownerState={{ value }} />
+                </ListItemIcon>
+                <ListItemText>{t(value)}</ListItemText>
+              </MenuItem>
+            ))}
           </MenuList>
         </DialogContent>
-      </Dialog>
+      </WorkspaceDialog>
     );
   }
 }
 
 ChangeThemeDialog.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   handleClose: PropTypes.func.isRequired,
   open: PropTypes.bool,
   selectedTheme: PropTypes.string.isRequired,
diff --git a/src/components/CollapsibleSection.js b/src/components/CollapsibleSection.js
index 8773c9b6d951d9c14ccbb6ec3000db74bd032811..04c5f7d5137bd28367c52808d6663c1f98b60d05 100644
--- a/src/components/CollapsibleSection.js
+++ b/src/components/CollapsibleSection.js
@@ -1,9 +1,10 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
-import KeyboardArrowDown from '@material-ui/icons/KeyboardArrowDownSharp';
-import KeyboardArrowUp from '@material-ui/icons/KeyboardArrowUpSharp';
-import MiradorMenuButton from '../containers/MiradorMenuButton';
+import Typography from '@mui/material/Typography';
+import Accordion from '@mui/material/Accordion';
+import AccordionDetails from '@mui/material/AccordionDetails';
+import AccordionSummary from '@mui/material/AccordionSummary';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
 
 /**
  * CollapsableSection ~
@@ -14,14 +15,12 @@ export class CollapsibleSection extends Component {
     super(props);
 
     this.state = { open: true };
-    this.toggleSection = this.toggleSection.bind(this);
+    this.handleChange = this.handleChange.bind(this);
   }
 
-  /** */
-  toggleSection() {
-    const { open } = this.state;
-
-    this.setState({ open: !open });
+  /** Control the accordion state so we can provide aria labeling */
+  handleChange(event, isExpanded) {
+    this.setState({ open: isExpanded });
   }
 
   /**
@@ -29,45 +28,28 @@ export class CollapsibleSection extends Component {
   */
   render() {
     const {
-      children, classes, id, label, t,
+      children, id, label, t,
     } = this.props;
     const { open } = this.state;
 
     return (
-      <>
-        <div className={classes.container}>
-          <Typography
-            className={classes.heading}
-            id={id}
-            onClick={this.toggleSection}
-            variant="overline"
-            component="h4"
-          >
+      <Accordion id={id} elevation={0} expanded={open} onChange={this.handleChange} disableGutters square variant="compact">
+        <AccordionSummary id={`${id}-header`} aria-controls={`${id}-content`} aria-label={t(open ? 'collapseSection' : 'expandSection', { section: label })} expandIcon={<ExpandMoreIcon />}>
+          <Typography variant="overline" component="h4">
             {label}
           </Typography>
-          <MiradorMenuButton
-            aria-label={
-              t(
-                open ? 'collapseSection' : 'expandSection',
-                { section: label },
-              )
-            }
-            aria-expanded={open}
-            className={classes.button}
-            onClick={this.toggleSection}
-          >
-            {open ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
-          </MiradorMenuButton>
-        </div>
-        {open && children}
-      </>
+        </AccordionSummary>
+        <AccordionDetails>
+          {children}
+        </AccordionDetails>
+      </Accordion>
     );
   }
 }
 
 CollapsibleSection.propTypes = {
   children: PropTypes.node.isRequired,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
+
   id: PropTypes.string.isRequired,
   label: PropTypes.string.isRequired,
   t: PropTypes.func.isRequired,
diff --git a/src/components/CollectionDialog.js b/src/components/CollectionDialog.js
index 3dc335ba9b3bfb13ef74ff4a66fc7348b59c129d..75fa641f14cc78bced024ae8cb14736effba434c 100644
--- a/src/components/CollectionDialog.js
+++ b/src/components/CollectionDialog.js
@@ -10,15 +10,32 @@ import {
   MenuList,
   MenuItem,
   Typography,
-} from '@material-ui/core';
-import ArrowBackIcon from '@material-ui/icons/ArrowBackSharp';
-import Skeleton from '@material-ui/lab/Skeleton';
+} from '@mui/material';
+import ArrowBackIcon from '@mui/icons-material/ArrowBackSharp';
+import Skeleton from '@mui/material/Skeleton';
+import { styled } from '@mui/material/styles';
 import asArray from '../lib/asArray';
 import { LabelValueMetadata } from './LabelValueMetadata';
 import CollapsibleSection from '../containers/CollapsibleSection';
 import ScrollIndicatedDialogContent from '../containers/ScrollIndicatedDialogContent';
 import ManifestInfo from '../containers/ManifestInfo';
 
+const StyledScrollIndicatedDialogContent = styled(ScrollIndicatedDialogContent)(() => ({
+  padding: (theme) => theme.spacing(1),
+}));
+
+const StyledCollectionMetadata = styled('div')(() => ({
+  '& .MuiPaper-root': {
+    background: 'transparent',
+  },
+  padding: (theme) => theme.spacing(2),
+}));
+
+const StyledCollectionFilter = styled('div')(() => ({
+  padding: (theme) => theme.spacing(2),
+  paddingTop: 0,
+}));
+
 /**
  * a dialog providing the possibility to select the collection
  */
@@ -108,37 +125,27 @@ export class CollectionDialog extends Component {
 
   /** */
   placeholder() {
-    const { classes } = this.props;
-
     return (
       <Dialog
-        className={classes.dialog}
+        variant="contained"
         onClose={this.hideDialog}
         open
         container={this.dialogContainer()}
-        BackdropProps={this.backdropProps()}
       >
-        <DialogTitle id="select-collection" disableTypography>
-          <Skeleton className={classes.placeholder} variant="text" />
+        <DialogTitle id="select-collection">
+          <Skeleton variant="text" />
         </DialogTitle>
         <ScrollIndicatedDialogContent>
-          <Skeleton className={classes.placeholder} variant="text" />
-          <Skeleton className={classes.placeholder} variant="text" />
+          <Skeleton variant="text" />
+          <Skeleton variant="text" />
         </ScrollIndicatedDialogContent>
       </Dialog>
     );
   }
 
-  /** */
-  backdropProps() {
-    const { classes } = this.props;
-    return { classes: { root: classes.dialog } };
-  }
-
   /** */
   render() {
     const {
-      classes,
       collection,
       error,
       isMultipart,
@@ -173,21 +180,20 @@ export class CollectionDialog extends Component {
 
     return (
       <Dialog
-        className={classes.dialog}
+        variant="contained"
         onClose={this.hideDialog}
         container={this.dialogContainer()}
-        BackdropProps={this.backdropProps()}
         open
       >
-        <DialogTitle id="select-collection" disableTypography>
+        <DialogTitle id="select-collection">
           <Typography component="div" variant="overline">
             { t(isMultipart ? 'multipartCollection' : 'collection') }
           </Typography>
-          <Typography variant="h3">
+          <Typography component="div" variant="h3">
             {CollectionDialog.getUseableLabel(manifest)}
           </Typography>
         </DialogTitle>
-        <ScrollIndicatedDialogContent className={classes.dialogContent}>
+        <StyledScrollIndicatedDialogContent>
           { collection && (
             <Button
               startIcon={<ArrowBackIcon />}
@@ -197,7 +203,7 @@ export class CollectionDialog extends Component {
             </Button>
           )}
 
-          <div className={classes.collectionMetadata}>
+          <StyledCollectionMetadata>
             <ManifestInfo manifestId={manifest.id} />
             <CollapsibleSection
               id="select-collection-rights"
@@ -221,15 +227,15 @@ export class CollectionDialog extends Component {
                 )
               }
             </CollapsibleSection>
-          </div>
-          <div className={classes.collectionFilter}>
+          </StyledCollectionMetadata>
+          <StyledCollectionFilter>
             {manifest.getTotalCollections() > 0 && (
               <Chip clickable color={currentFilter === 'collections' ? 'primary' : 'default'} onClick={() => this.setFilter('collections')} label={t('totalCollections', { count: manifest.getTotalCollections() })} />
             )}
             {manifest.getTotalManifests() > 0 && (
               <Chip clickable color={currentFilter === 'manifests' ? 'primary' : 'default'} onClick={() => this.setFilter('manifests')} label={t('totalManifests', { count: manifest.getTotalManifests() })} />
             )}
-          </div>
+          </StyledCollectionFilter>
           { currentFilter === 'collections' && (
             <MenuList>
               {
@@ -237,7 +243,7 @@ export class CollectionDialog extends Component {
                   <MenuItem
                     key={c.id}
                     onClick={() => { this.selectCollection(c); }}
-                    className={classes.collectionItem}
+                    variant="multiline"
                   >
                     {CollectionDialog.getUseableLabel(c)}
                   </MenuItem>
@@ -252,7 +258,7 @@ export class CollectionDialog extends Component {
                   <MenuItem
                     key={m.id}
                     onClick={() => { this.selectManifest(m); }}
-                    className={classes.collectionItem}
+                    variant="multiline"
                   >
                     {CollectionDialog.getUseableLabel(m)}
                   </MenuItem>
@@ -260,7 +266,7 @@ export class CollectionDialog extends Component {
               }
             </MenuList>
           )}
-        </ScrollIndicatedDialogContent>
+        </StyledScrollIndicatedDialogContent>
         <DialogActions>
           <Button onClick={this.hideDialog}>
             {t('close')}
@@ -273,7 +279,6 @@ export class CollectionDialog extends Component {
 
 CollectionDialog.propTypes = {
   addWindow: PropTypes.func.isRequired,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   collection: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   collectionPath: PropTypes.arrayOf(PropTypes.string),
   container: PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
diff --git a/src/components/CollectionInfo.js b/src/components/CollectionInfo.js
index 4cd3d3961e5bf804d24687e703199d8b0e6b4d61..ead13a799bbd0b346fa4f1e5b0a4124c395e2700 100644
--- a/src/components/CollectionInfo.js
+++ b/src/components/CollectionInfo.js
@@ -1,8 +1,8 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Button from '@material-ui/core/Button';
-import Typography from '@material-ui/core/Typography';
-import ViewListIcon from '@material-ui/icons/ViewListSharp';
+import Button from '@mui/material/Button';
+import Typography from '@mui/material/Typography';
+import ViewListIcon from '@mui/icons-material/ViewListSharp';
 import CollapsibleSection from '../containers/CollapsibleSection';
 
 /**
diff --git a/src/components/CompanionArea.js b/src/components/CompanionArea.js
index bdf7610b6e5e06f26505d86cce8b4622818ed98b..b73350d644204d6e36febe1491f0be5ff69431a9 100644
--- a/src/components/CompanionArea.js
+++ b/src/components/CompanionArea.js
@@ -1,19 +1,58 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Slide from '@material-ui/core/Slide';
-import ArrowLeftIcon from '@material-ui/icons/ArrowLeftSharp';
-import ArrowRightIcon from '@material-ui/icons/ArrowRightSharp';
+import { styled } from '@mui/material/styles';
+import Slide from '@mui/material/Slide';
+import ArrowLeftIcon from '@mui/icons-material/ArrowLeftSharp';
+import ArrowRightIcon from '@mui/icons-material/ArrowRightSharp';
+import classNames from 'classnames';
 import CompanionWindowFactory from '../containers/CompanionWindowFactory';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 import ns from '../config/css-ns';
 
+const Root = styled('div', { name: 'CompanionArea', slot: 'root' })(({ ownerState, theme }) => ({
+  display: 'flex',
+  minHeight: 0,
+  position: 'relative',
+  zIndex: theme.zIndex.appBar - 2,
+  ...((ownerState.position === 'bottom' || ownerState.position === 'far-bottom') && {
+    flexDirection: 'column',
+    width: '100%',
+  }),
+}));
+
+const Container = styled('div', { name: 'CompanionArea', slot: 'container' })(({ ownerState }) => ({
+  display: ownerState?.companionAreaOpen ? 'flex' : 'none',
+  ...((ownerState?.position === 'bottom' || ownerState?.position === 'far-bottom') && {
+    flexDirection: 'column',
+    width: '100%',
+  }),
+  ...((ownerState?.position === 'left' && (ownerState?.companionWindowIds && ownerState.companionWindowIds.length > 0)) && {
+    minWidth: '235px',
+  }),
+}));
+
+const StyledToggle = styled('div', { name: 'CompanionArea', slot: 'toggle' })(({ theme }) => ({
+  alignItems: 'center',
+  backgroundColor: theme.palette.background.paper,
+  border: `1px solid ${theme.palette.mode === 'dark' ? theme.palette.divider : theme.palette.shades?.dark}`,
+  borderInlineStart: 0,
+  borderRadius: 0,
+  display: 'inline-flex',
+  height: '48px',
+  left: '100%',
+  marginTop: '1rem',
+  overflow: 'hidden',
+  padding: 2,
+  position: 'absolute',
+  width: '23px',
+  zIndex: theme.zIndex.drawer,
+}));
+
 /** */
 export class CompanionArea extends Component {
   /** */
   areaLayoutClass() {
-    const {
-      classes, position,
-    } = this.props;
+    const { classes, position } = this.props;
 
     return (position === 'bottom' || position === 'far-bottom') ? classes.horizontal : null;
   }
@@ -51,45 +90,44 @@ export class CompanionArea extends Component {
   /** */
   render() {
     const {
-      classes, companionWindowIds, companionAreaOpen, setCompanionAreaOpen,
+      className,
+      companionWindowIds, companionAreaOpen, setCompanionAreaOpen,
       position, sideBarOpen, t, windowId,
     } = this.props;
-
+    const classes = classNames(this.areaLayoutClass(), ns(`companion-area-${position}`), className);
     return (
-      <div className={[classes.root, this.areaLayoutClass(), ns(`companion-area-${position}`)].join(' ')}>
+      <Root ownerState={this.props} className={classes}>
         <Slide in={companionAreaOpen} direction={this.slideDirection()}>
-          <div className={[ns('companion-windows'), companionWindowIds.length > 0 && classes[position], this.areaLayoutClass()].join(' ')} style={{ display: companionAreaOpen ? 'flex' : 'none' }}>
-            {
-              companionWindowIds.map(id => (
-                <CompanionWindowFactory id={id} key={id} windowId={windowId} />
-              ))
-            }
-          </div>
+          <Container
+            ownerState={this.props}
+            className={`${ns('companion-windows')}`}
+          >
+            {companionWindowIds.map((id) => (
+              <CompanionWindowFactory id={id} key={id} windowId={windowId} />
+            ))}
+          </Container>
         </Slide>
-        {
-          setCompanionAreaOpen && position === 'left' && sideBarOpen && companionWindowIds.length > 0
-          && (
-            <div className={classes.toggle}>
-              <MiradorMenuButton
-                aria-expanded={companionAreaOpen}
-                aria-label={companionAreaOpen ? t('collapseSidePanel') : t('expandSidePanel')}
-                className={classes.toggleButton}
-                key={companionAreaOpen ? 'collapse' : 'expand'}
-                onClick={() => { setCompanionAreaOpen(windowId, !companionAreaOpen); }}
-                TooltipProps={{ placement: 'right' }}
-              >
-                {this.collapseIcon()}
-              </MiradorMenuButton>
-            </div>
-          )
-        }
-      </div>
+        {setCompanionAreaOpen && position === 'left' && sideBarOpen && companionWindowIds.length > 0 && (
+        <StyledToggle>
+          <MiradorMenuButton
+            aria-expanded={companionAreaOpen}
+            aria-label={companionAreaOpen ? t('collapseSidePanel') : t('expandSidePanel')}
+            edge="start"
+            onClick={() => { setCompanionAreaOpen(windowId, !companionAreaOpen); }}
+            TooltipProps={{ placement: 'right' }}
+          >
+            {this.collapseIcon()}
+          </MiradorMenuButton>
+        </StyledToggle>
+        )}
+      </Root>
     );
   }
 }
 
 CompanionArea.propTypes = {
   classes: PropTypes.objectOf(PropTypes.string),
+  className: PropTypes.string,
   companionAreaOpen: PropTypes.bool.isRequired,
   companionWindowIds: PropTypes.arrayOf(PropTypes.string).isRequired,
   direction: PropTypes.string.isRequired,
@@ -102,6 +140,7 @@ CompanionArea.propTypes = {
 
 CompanionArea.defaultProps = {
   classes: {},
+  className: undefined,
   setCompanionAreaOpen: () => {},
   sideBarOpen: false,
 };
diff --git a/src/components/CompanionWindow.js b/src/components/CompanionWindow.js
index 9cf4fe29a4e55f7576b7b3a6af724b0a87a4297a..8a31ce2fb1b8a4b1127bcdec3e1d9566b7911241 100644
--- a/src/components/CompanionWindow.js
+++ b/src/components/CompanionWindow.js
@@ -1,15 +1,25 @@
 import { Children, cloneElement, Component } from 'react';
 import PropTypes from 'prop-types';
-import CloseIcon from '@material-ui/icons/CloseSharp';
-import OpenInNewIcon from '@material-ui/icons/OpenInNewSharp';
-import MoveIcon from '@material-ui/icons/DragIndicatorSharp';
-import Paper from '@material-ui/core/Paper';
-import Typography from '@material-ui/core/Typography';
-import Toolbar from '@material-ui/core/Toolbar';
+import { styled } from '@mui/material/styles';
+import CloseIcon from '@mui/icons-material/CloseSharp';
+import OpenInNewIcon from '@mui/icons-material/OpenInNewSharp';
+import MoveIcon from '@mui/icons-material/DragIndicatorSharp';
+import Paper from '@mui/material/Paper';
+import Typography from '@mui/material/Typography';
+import Toolbar from '@mui/material/Toolbar';
 import { Rnd } from 'react-rnd';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 import ns from '../config/css-ns';
 
+const Root = styled(Paper, { name: 'CompanionWindow', slot: 'root' })({});
+const StyledToolbar = styled(Toolbar, { name: 'CompanionWindow', slot: 'toolbar' })({});
+const StyledTitle = styled(Typography, { name: 'CompanionWindow', slot: 'title' })({});
+const StyledTitleControls = styled('div', { name: 'CompanionWindow', slot: 'controls' })({});
+const Contents = styled(Paper, { name: 'CompanionWindow', slot: 'contents' })({});
+const StyledRnd = styled(Rnd, { name: 'CompanionWindow', slot: 'resize' })({});
+const StyledPositionButton = styled(MiradorMenuButton, { name: 'CompanionWindow', slot: 'positionButton' })({});
+const StyledCloseButton = styled(MiradorMenuButton, { name: 'CompanionWindow', slot: 'closeButton' })({});
+
 /**
  * CompanionWindow
  */
@@ -69,7 +79,7 @@ export class CompanionWindow extends Component {
     const {
       ariaLabel, classes, paperClassName, onCloseClick, updateCompanionWindow, isDisplayed,
       position, t, title, children, titleControls, size,
-      defaultSidebarPanelWidth, defaultSidebarPanelHeight,
+      defaultSidebarPanelWidth, defaultSidebarPanelHeight, innerRef,
     } = this.props;
 
     const isBottom = (position === 'bottom' || position === 'far-bottom');
@@ -87,19 +97,21 @@ export class CompanionWindow extends Component {
     });
 
     return (
-      <Paper
-        className={[classes.root, position === 'bottom' ? classes.horizontal : classes.vertical, classes[`companionWindow-${position}`], ns(`companion-window-${position}`), paperClassName].join(' ')}
+      <Root
+        ownerState={this.props}
+        ref={innerRef}
         style={{
           display: isDisplayed ? null : 'none',
           order: position === 'left' ? -1 : null,
         }}
+        className={[ns(`companion-window-${position}`), paperClassName, position === 'bottom' ? classes.horizontal : classes.vertical].join(' ')}
         square
         component="aside"
         aria-label={ariaLabel || title}
       >
-        <Rnd
-          className={[classes.rnd]}
-          style={{ display: 'flex', position: 'relative' }}
+        <StyledRnd
+          style={{ display: 'inherit', position: 'inherit' }}
+          ownerState={this.props}
           default={{
             height: isBottom ? defaultSidebarPanelHeight : '100%',
             width: isBottom ? 'auto' : defaultSidebarPanelWidth,
@@ -110,18 +122,12 @@ export class CompanionWindow extends Component {
           minWidth={position === 'left' ? 235 : 100}
         >
 
-          <Toolbar
-            className={[
-              classes.toolbar,
-              classes.companionWindowHeader,
-              size.width < 370 ? classes.small : null,
-              ns('companion-window-header'),
-            ].join(' ')}
+          <StyledToolbar
+            variant="dense"
+            className={[ns('companion-window-header'), size.width < 370 ? classes.small : null].join(' ')}
             disableGutters
           >
-            <Typography variant="h3" className={classes.windowSideBarTitle}>
-              {title}
-            </Typography>
+            <StyledTitle variant="h3">{title}</StyledTitle>
             {
               position === 'left'
                 ? updateCompanionWindow
@@ -137,49 +143,50 @@ export class CompanionWindow extends Component {
                   <>
                     {
                       updateCompanionWindow && (
-                        <MiradorMenuButton
+                        <StyledPositionButton
                           aria-label={position === 'bottom' ? t('moveCompanionWindowToRight') : t('moveCompanionWindowToBottom')}
-                          className={classes.positionButton}
                           onClick={() => { updateCompanionWindow({ position: position === 'bottom' ? 'right' : 'bottom' }); }}
                         >
                           <MoveIcon />
-                        </MiradorMenuButton>
+                        </StyledPositionButton>
                       )
                     }
-                    <MiradorMenuButton
+                    <StyledCloseButton
+                      sx={{
+                        ...(size.width < 370 && {
+                          order: 'unset',
+                        }),
+                      }}
                       aria-label={t('closeCompanionWindow')}
-                      className={classes.closeButton}
                       onClick={onCloseClick}
                     >
                       <CloseIcon />
-                    </MiradorMenuButton>
+                    </StyledCloseButton>
                   </>
                 )
             }
             {
               titleControls && (
-                <div
-                  className={[
-                    classes.titleControls,
-                    isBottom
-                      ? classes.companionWindowTitleControlsBottom
-                      : classes.companionWindowTitleControls,
-                    ns('companion-window-title-controls'),
-                  ].join(' ')}
+                <StyledTitleControls
+                  ownerState={{ position }}
+                  sx={{
+                    order: isBottom || size.width < 370 ? 'unset' : 1000,
+                  }}
+                  className={ns('companion-window-title-controls')}
                 >
                   {titleControls}
-                </div>
+                </StyledTitleControls>
               )
             }
-          </Toolbar>
-          <Paper
-            className={[classes.content, ns('scrollto-scrollable')].join(' ')}
+          </StyledToolbar>
+          <Contents
+            className={ns('scrollto-scrollable')}
             elevation={0}
           >
             {childrenWithAdditionalProps}
-          </Paper>
-        </Rnd>
-      </Paper>
+          </Contents>
+        </StyledRnd>
+      </Root>
     );
   }
 }
@@ -187,10 +194,14 @@ export class CompanionWindow extends Component {
 CompanionWindow.propTypes = {
   ariaLabel: PropTypes.string,
   children: PropTypes.node,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
+  classes: PropTypes.objectOf(PropTypes.string),
   defaultSidebarPanelHeight: PropTypes.number,
   defaultSidebarPanelWidth: PropTypes.number,
   direction: PropTypes.string.isRequired,
+  innerRef: PropTypes.oneOfType([
+    PropTypes.func,
+    PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
+  ]),
   isDisplayed: PropTypes.bool,
   onCloseClick: PropTypes.func,
   paperClassName: PropTypes.string,
@@ -208,8 +219,10 @@ CompanionWindow.propTypes = {
 CompanionWindow.defaultProps = {
   ariaLabel: undefined,
   children: undefined,
+  classes: {},
   defaultSidebarPanelHeight: 201,
   defaultSidebarPanelWidth: 235,
+  innerRef: undefined,
   isDisplayed: false,
   onCloseClick: () => {},
   paperClassName: '',
diff --git a/src/components/CompanionWindowSection.js b/src/components/CompanionWindowSection.js
new file mode 100644
index 0000000000000000000000000000000000000000..312164e85b190960ee6e0adab8b030d3146104fd
--- /dev/null
+++ b/src/components/CompanionWindowSection.js
@@ -0,0 +1,8 @@
+import { styled } from '@mui/material/styles';
+
+export const CompanionWindowSection = styled('div', { name: 'CompanionWindowSection', slot: 'root' })(({ theme }) => ({
+  paddingBlockEnd: theme.spacing(1),
+  paddingBlockStart: theme.spacing(2),
+  paddingInlineEnd: theme.spacing(1),
+  paddingInlineStart: theme.spacing(2),
+}));
diff --git a/src/components/ErrorContent.js b/src/components/ErrorContent.js
index d6e996ece45f003bfe8bb20b09483454a870409d..b179f769530332094f51158ba1dd664ee310f3c1 100644
--- a/src/components/ErrorContent.js
+++ b/src/components/ErrorContent.js
@@ -1,19 +1,34 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Accordion from '@material-ui/core/Accordion';
-import AccordionSummary from '@material-ui/core/AccordionSummary';
-import AccordionDetails from '@material-ui/core/AccordionDetails';
-import Typography from '@material-ui/core/Typography';
-import Alert from '@material-ui/lab/Alert';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import { styled } from '@mui/material/styles';
+import Accordion from '@mui/material/Accordion';
+import AccordionSummary from '@mui/material/AccordionSummary';
+import AccordionDetails from '@mui/material/AccordionDetails';
+import Stack from '@mui/material/Stack';
+import Alert from '@mui/material/Alert';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
 import { PluginHook } from './PluginHook';
 
+const ErrorStackTrace = styled('pre', { name: 'ErrorContent', slot: 'stacktrace' })({
+  overflowY: 'scroll',
+});
+
+const ErrorMetadata = styled('pre', { name: 'ErrorContent', slot: 'metadata' })({
+  height: '100px',
+  overflowY: 'scroll',
+});
+
+const InlineAccordion = styled(Accordion, { name: 'ErrorContent', slot: 'accordion' })({
+  backgroundColor: 'inherit',
+  color: 'inherit',
+  margin: 0,
+});
+
 /** */
 export class ErrorContent extends Component {
   /** */
   render() {
     const {
-      classes,
       error,
       metadata,
       showJsError,
@@ -23,34 +38,28 @@ export class ErrorContent extends Component {
     if (!showJsError) return null;
 
     return (
-      <>
-        <Alert elevation={6} variant="filled" severity="error">
-          {t('errorDialogTitle')}
-        </Alert>
-
+      <Alert elevation={6} variant="filled" severity="error">
+        {t('errorDialogTitle')}
         {showJsError && (
-          <Accordion square className={classes.alert}>
-            <AccordionSummary
-              expandIcon={<ExpandMoreIcon />}
-            >
-              <Typography>{t('jsError', { message: error.message, name: error.name })}</Typography>
+          <InlineAccordion elevation={2} square>
+            <AccordionSummary sx={{ marginInlineStart: '-1rem' }} expandIcon={<ExpandMoreIcon sx={{ color: '#fff' }} />}>
+              {t('jsError', { message: error.message, name: error.name })}
             </AccordionSummary>
-            <AccordionDetails className={classes.details}>
-              <pre>{ t('jsStack', { stack: error.stack }) }</pre>
-              { metadata && (
-                <pre>{JSON.stringify(metadata, null, 2)}</pre>
-              )}
+            <AccordionDetails>
+              <Stack>
+                <ErrorStackTrace>{t('jsStack', { stack: error.stack })}</ErrorStackTrace>
+                {metadata && <ErrorMetadata>{JSON.stringify(metadata, null, 2)}</ErrorMetadata>}
+              </Stack>
             </AccordionDetails>
-          </Accordion>
+          </InlineAccordion>
         )}
         <PluginHook {...this.props} />
-      </>
+      </Alert>
     );
   }
 }
 
 ErrorContent.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   error: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
   metadata: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   showJsError: PropTypes.bool,
diff --git a/src/components/ErrorDialog.js b/src/components/ErrorDialog.js
index e9f5b342ae0a07d856a68df8d7a9927eced27d70..5828a6b98b4f21249f9a0e808945c418f82ce055 100644
--- a/src/components/ErrorDialog.js
+++ b/src/components/ErrorDialog.js
@@ -1,10 +1,10 @@
 import { Component } from 'react';
-import Dialog from '@material-ui/core/Dialog';
-import DialogContent from '@material-ui/core/DialogContent';
-import DialogTitle from '@material-ui/core/DialogTitle';
+import Dialog from '@mui/material/Dialog';
+import DialogContent from '@mui/material/DialogContent';
+import DialogTitle from '@mui/material/DialogTitle';
 import PropTypes from 'prop-types';
-import { DialogActions, DialogContentText, Typography } from '@material-ui/core';
-import Button from '@material-ui/core/Button';
+import { DialogActions, DialogContentText } from '@mui/material';
+import Button from '@mui/material/Button';
 import { isUndefined } from 'lodash';
 
 /**
@@ -28,8 +28,8 @@ export class ErrorDialog extends Component {
         onClose={() => removeError(error.id)}
         open={hasError}
       >
-        <DialogTitle id="error-dialog-title" disableTypography>
-          <Typography variant="h2">{t('errorDialogTitle')}</Typography>
+        <DialogTitle id="error-dialog-title">
+          {t('errorDialogTitle')}
         </DialogTitle>
         <DialogContent>
           <DialogContentText variant="body2" noWrap color="inherit">
diff --git a/src/components/FullScreenButton.js b/src/components/FullScreenButton.js
index 2038fa9bc09f1675a5b0c9d31ea565f308419eee..0aabc6722ef9a9192bfd431c1464a9ea05f7e380 100644
--- a/src/components/FullScreenButton.js
+++ b/src/components/FullScreenButton.js
@@ -1,6 +1,6 @@
 import { Component } from 'react';
-import FullscreenIcon from '@material-ui/icons/FullscreenSharp';
-import FullscreenExitIcon from '@material-ui/icons/FullscreenExitSharp';
+import FullscreenIcon from '@mui/icons-material/FullscreenSharp';
+import FullscreenExitIcon from '@mui/icons-material/FullscreenExitSharp';
 import PropTypes from 'prop-types';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 import FullScreenContext from '../contexts/FullScreenContext';
diff --git a/src/components/GalleryView.js b/src/components/GalleryView.js
index 66d0348db419d1cf8e1ef5925c7cdede472768ed..1738f56baae0c98c0373d9d84d5e9272ecebccfe 100644
--- a/src/components/GalleryView.js
+++ b/src/components/GalleryView.js
@@ -1,8 +1,20 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Paper from '@material-ui/core/Paper';
+import { styled } from '@mui/material/styles';
+import Paper from '@mui/material/Paper';
 import GalleryViewThumbnail from '../containers/GalleryViewThumbnail';
 
+const Root = styled(Paper, { name: 'GalleryView', slot: 'root' })(({ theme }) => ({
+  alignItems: 'flex-start',
+  display: 'flex',
+  flexDirection: 'row',
+  flexWrap: 'wrap',
+  overflowX: 'hidden',
+  overflowY: 'scroll',
+  padding: '50px 0 50px 20px',
+  width: '100%',
+}));
+
 /**
  * Renders a GalleryView overview of the manifest.
  */
@@ -12,17 +24,16 @@ export class GalleryView extends Component {
    */
   render() {
     const {
-      canvases, classes, viewingDirection, windowId,
+      canvases, viewingDirection, windowId,
     } = this.props;
     const htmlDir = viewingDirection === 'right-to-left' ? 'rtl' : 'ltr';
     return (
-      <Paper
+      <Root
         component="section"
         aria-label="gallery section"
         dir={htmlDir}
         square
         elevation={0}
-        className={classes.galleryContainer}
         id={`${windowId}-gallery`}
       >
         {
@@ -34,19 +45,17 @@ export class GalleryView extends Component {
             />
           ))
         }
-      </Paper>
+      </Root>
     );
   }
 }
 
 GalleryView.propTypes = {
   canvases: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
-  classes: PropTypes.objectOf(PropTypes.string),
   viewingDirection: PropTypes.string,
   windowId: PropTypes.string.isRequired,
 };
 
 GalleryView.defaultProps = {
-  classes: {},
   viewingDirection: '',
 };
diff --git a/src/components/GalleryViewThumbnail.js b/src/components/GalleryViewThumbnail.js
index e475c98518f7307d6e3641fc56a54b8460ea48bc..efa36629d24ccc1240441ad26f2017e9a55b6948 100644
--- a/src/components/GalleryViewThumbnail.js
+++ b/src/components/GalleryViewThumbnail.js
@@ -1,14 +1,52 @@
 import { createRef, Component } from 'react';
 import PropTypes from 'prop-types';
-import Avatar from '@material-ui/core/Avatar';
-import Chip from '@material-ui/core/Chip';
-import AnnotationIcon from '@material-ui/icons/CommentSharp';
-import SearchIcon from '@material-ui/icons/SearchSharp';
-import classNames from 'classnames';
+import { styled } from '@mui/material/styles';
+import Chip from '@mui/material/Chip';
+import AnnotationIcon from '@mui/icons-material/CommentSharp';
+import SearchIcon from '@mui/icons-material/SearchSharp';
 import { InView } from 'react-intersection-observer';
-import MiradorCanvas from '../lib/MiradorCanvas';
 import IIIFThumbnail from '../containers/IIIFThumbnail';
 
+const Root = styled('div', { name: 'GalleryView', slot: 'thumbnail' })(({ ownerState, theme }) => ({
+  '&:focus': {
+    outline: 'none',
+  },
+  '&:hover': {
+    backgroundColor: theme.palette.action.hover,
+  },
+  border: '2px solid transparent',
+  ...(ownerState.selected && {
+    borderColor: theme.palette.primary.main,
+  }),
+  ...(!ownerState.selected && ownerState.searchAnnotationsCount > 0 && {
+    borderColor: theme.palette.action.selected,
+  }),
+  cursor: 'pointer',
+  display: 'inline-block',
+  margin: theme.spacing(1, 0.5),
+  maxHeight: ownerState.config.height + 45,
+  minWidth: '60px',
+  overflow: 'hidden',
+  padding: theme.spacing(0.5),
+  position: 'relative',
+  width: 'min-content',
+}));
+
+const StyledChipsContainer = styled('div', { name: 'GalleryView', slot: 'chipArea' })(({ theme }) => ({
+  display: 'flex',
+  flexDirection: 'column',
+  gap: theme.spacing(0.25),
+  position: 'absolute',
+  right: 0,
+  top: 0,
+}));
+
+const AnnotationChip = styled(Chip, { name: 'GalleryView', slot: 'chip' })(({ theme }) => ({
+  backgroundColor: theme.palette.annotations.chipBackground,
+  opacity: 0.875,
+  textAlign: 'right',
+}));
+
 /**
  * Represents a WindowViewer in the mirador workspace. Responsible for mounting
  * OSD and Navigation
@@ -102,22 +140,15 @@ export class GalleryViewThumbnail extends Component {
   render() {
     const {
       annotationsCount, searchAnnotationsCount,
-      canvas, classes, config, selected,
+      canvas, config, selected,
     } = this.props;
 
-    const miradorCanvas = new MiradorCanvas(canvas);
-
     return (
       <InView onChange={this.handleIntersection}>
-        <div
-          key={canvas.index}
-          className={
-            classNames(
-              classes.galleryViewItem,
-              selected ? classes.selected : '',
-              searchAnnotationsCount > 0 ? classes.hasAnnotations : '',
-            )
-          }
+        <Root
+          ownerState={this.props}
+          key={canvas.id || canvas.index}
+          className={selected ? 'selected' : ''}
           onClick={this.handleSelect}
           onKeyUp={this.handleKey}
           ref={this.myRef}
@@ -128,45 +159,27 @@ export class GalleryViewThumbnail extends Component {
             resource={canvas}
             labelled
             variant="outside"
-            maxWidth={config.width}
             maxHeight={config.height}
-            style={{
-              margin: '0 auto',
-              maxWidth: `${Math.ceil(config.height * miradorCanvas.aspectRatio)}px`,
-            }}
+            maxWidth={config.width}
           >
-            <div className={classes.chips}>
-              { searchAnnotationsCount > 0 && (
-                <Chip
-                  avatar={(
-                    <Avatar className={classes.avatar} classes={{ circle: classes.avatarIcon }}>
-                      <SearchIcon fontSize="small" />
-                    </Avatar>
-                  )}
+            <StyledChipsContainer>
+              {searchAnnotationsCount > 0 && (
+                <AnnotationChip
+                  icon={<SearchIcon fontSize="small" />}
                   label={searchAnnotationsCount}
-                  className={classNames(classes.searchChip)}
                   size="small"
                 />
               )}
-              { (annotationsCount || 0) > 0 && (
-                <Chip
-                  avatar={(
-                    <Avatar className={classes.avatar} classes={{ circle: classes.avatarIcon }}>
-                      <AnnotationIcon className={classes.annotationIcon} />
-                    </Avatar>
-                  )}
+              {annotationsCount > 0 && (
+                <AnnotationChip
+                  icon={<AnnotationIcon fontSize="small" />}
                   label={annotationsCount}
-                  className={
-                    classNames(
-                      classes.annotationsChip,
-                    )
-                  }
                   size="small"
                 />
               )}
-            </div>
+            </StyledChipsContainer>
           </IIIFThumbnail>
-        </div>
+        </Root>
       </InView>
     );
   }
@@ -175,7 +188,6 @@ export class GalleryViewThumbnail extends Component {
 GalleryViewThumbnail.propTypes = {
   annotationsCount: PropTypes.number,
   canvas: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   config: PropTypes.shape({
     height: PropTypes.number,
     width: PropTypes.number,
diff --git a/src/components/IIIFDropTarget.js b/src/components/IIIFDropTarget.js
index 8b48beefc91d35ca4d149023e1f3846f58c4012f..6a15f7123055df530e6f5576d93d48176f3c8697 100644
--- a/src/components/IIIFDropTarget.js
+++ b/src/components/IIIFDropTarget.js
@@ -1,7 +1,7 @@
 import PropTypes from 'prop-types';
-import Backdrop from '@material-ui/core/Backdrop';
-import InsertDriveFileSharpIcon from '@material-ui/icons/InsertDriveFileSharp';
-import { grey } from '@material-ui/core/colors';
+import Backdrop from '@mui/material/Backdrop';
+import InsertDriveFileSharpIcon from '@mui/icons-material/InsertDriveFileSharp';
+import { grey } from '@mui/material/colors';
 import { v4 as uuid } from 'uuid';
 import { NativeTypes } from 'react-dnd-html5-backend';
 import { useDrop } from 'react-dnd';
diff --git a/src/components/IIIFThumbnail.js b/src/components/IIIFThumbnail.js
index ade25534a6495af499aa63f2707a98dcf10f8756..1fd61e66fe9a976cee7a569d17c75eb5f580ccf5 100644
--- a/src/components/IIIFThumbnail.js
+++ b/src/components/IIIFThumbnail.js
@@ -2,17 +2,27 @@ import {
   Component, useMemo, useEffect, useState,
 } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
+import { styled } from '@mui/material/styles';
 import { useInView } from 'react-intersection-observer';
-import classNames from 'classnames';
 import getThumbnail from '../lib/ThumbnailFactory';
 
+const Root = styled('div', { name: 'IIIFThumbnail', slot: 'root' })({});
+
+const Label = styled('span', { name: 'IIIFThumbnail', slot: 'label' })(({ theme }) => ({
+  ...theme.typography.caption,
+}));
+
+const Image = styled('img', { name: 'IIIFThumbnail', slot: 'image' })(() => ({
+  height: 'auto',
+  width: 'auto',
+}));
+
 /**
  * A lazy-loaded image that uses IntersectionObserver to determine when to
  * try to load the image (or even calculate that the image url/height/width are)
  */
 const LazyLoadedImage = ({
-  placeholder, style = {}, thumbnail, resource, maxHeight, maxWidth, thumbnailsConfig, ...props
+  border, placeholder, style = {}, thumbnail, resource, maxHeight, maxWidth, thumbnailsConfig, ...props
 }) => {
   const { ref, inView } = useInView();
   const [loaded, setLoaded] = useState(false);
@@ -38,9 +48,14 @@ const LazyLoadedImage = ({
   }, [resource, thumbnail, maxWidth, maxHeight, thumbnailsConfig]);
 
   const imageStyles = useMemo(() => {
-    const styleProps = { height: 'auto', width: 'auto' };
+    const styleProps = {
+      height: undefined,
+      maxHeight: undefined,
+      maxWidth: undefined,
+      width: undefined,
+    };
 
-    if (!image) return { ...style, height: maxHeight || 'auto', width: maxWidth || 'auto' };
+    if (!image) return { ...style, height: maxHeight, width: maxWidth };
 
     const { height: thumbHeight, width: thumbWidth } = image;
     if (thumbHeight && thumbWidth) {
@@ -87,7 +102,8 @@ const LazyLoadedImage = ({
   const { url: src = placeholder } = (loaded && (thumbnail || image)) || {};
 
   return (
-    <img
+    <Image
+      ownerState={{ border }}
       ref={ref}
       alt=""
       role="presentation"
@@ -99,6 +115,7 @@ const LazyLoadedImage = ({
 };
 
 LazyLoadedImage.propTypes = {
+  border: PropTypes.bool,
   maxHeight: PropTypes.number.isRequired,
   maxWidth: PropTypes.number.isRequired,
   placeholder: PropTypes.string.isRequired,
@@ -113,6 +130,7 @@ LazyLoadedImage.propTypes = {
 };
 
 LazyLoadedImage.defaultProps = {
+  border: false,
   style: {},
   thumbnail: null,
   thumbnailsConfig: {},
@@ -142,8 +160,8 @@ export class IIIFThumbnail extends Component {
    */
   render() {
     const {
+      border,
       children,
-      classes,
       imagePlaceholder,
       labelled,
       maxHeight,
@@ -152,11 +170,10 @@ export class IIIFThumbnail extends Component {
       style,
       thumbnail,
       thumbnailsConfig,
-      variant,
     } = this.props;
 
     return (
-      <div className={classNames(classes.root, { [classes[`${variant}Root`]]: variant })}>
+      <Root ownerState={this.props}>
         <LazyLoadedImage
           placeholder={imagePlaceholder}
           thumbnail={thumbnail}
@@ -165,25 +182,23 @@ export class IIIFThumbnail extends Component {
           maxWidth={maxWidth}
           thumbnailsConfig={thumbnailsConfig}
           style={style}
-          className={classes.image}
+          border={border}
         />
 
         { labelled && (
-          <div className={classNames(classes.label, { [classes[`${variant}Label`]]: variant })}>
-            <Typography variant="caption" classes={{ root: classNames(classes.caption, { [classes[`${variant}Caption`]]: variant }) }}>
-              {this.label()}
-            </Typography>
-          </div>
+          <Label ownerState={this.props}>
+            {this.label()}
+          </Label>
         )}
         {children}
-      </div>
+      </Root>
     );
   }
 }
 
 IIIFThumbnail.propTypes = {
+  border: PropTypes.bool,
   children: PropTypes.node,
-  classes: PropTypes.objectOf(PropTypes.string),
   imagePlaceholder: PropTypes.string,
   label: PropTypes.string,
   labelled: PropTypes.bool,
@@ -197,12 +212,12 @@ IIIFThumbnail.propTypes = {
     width: PropTypes.number,
   }),
   thumbnailsConfig: PropTypes.object, // eslint-disable-line react/forbid-prop-types
-  variant: PropTypes.oneOf(['inside', 'outside']),
+  variant: PropTypes.oneOf(['inside', 'outside']), // eslint-disable-line react/no-unused-prop-types
 };
 
 IIIFThumbnail.defaultProps = {
+  border: false,
   children: null,
-  classes: {},
   // Transparent "gray"
   imagePlaceholder: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mMMDQmtBwADgwF/Op8FmAAAAABJRU5ErkJggg==',
   label: undefined,
diff --git a/src/components/LabelValueMetadata.js b/src/components/LabelValueMetadata.js
index 9cb73df2718649d39f1ae71470b0841d926167d2..b1fe6c9a29d5d11e9f76a56394d30ace140f5fa1 100644
--- a/src/components/LabelValueMetadata.js
+++ b/src/components/LabelValueMetadata.js
@@ -1,6 +1,6 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
+import Typography from '@mui/material/Typography';
 import SanitizedHtml from '../containers/SanitizedHtml';
 import ns from '../config/css-ns';
 
diff --git a/src/components/LanguageSettings.js b/src/components/LanguageSettings.js
index 7901c4e440ada6bd9e5f251b71998158a850ed6a..f0048c4788abbc9b9ef50d49818dbd40cf4f7456 100644
--- a/src/components/LanguageSettings.js
+++ b/src/components/LanguageSettings.js
@@ -1,8 +1,8 @@
 import { Component } from 'react';
-import ListItemIcon from '@material-ui/core/ListItemIcon';
-import ListItemText from '@material-ui/core/ListItemText';
-import MenuItem from '@material-ui/core/MenuItem';
-import CheckIcon from '@material-ui/icons/CheckSharp';
+import ListItemIcon from '@mui/material/ListItemIcon';
+import ListItemText from '@mui/material/ListItemText';
+import MenuItem from '@mui/material/MenuItem';
+import CheckIcon from '@mui/icons-material/CheckSharp';
 import PropTypes from 'prop-types';
 
 /**
@@ -23,7 +23,6 @@ export class LanguageSettings extends Component {
         {
           languages.map(language => (
             <MenuItem
-              button={!language.current}
               key={language.locale}
               onClick={() => { handleClick(language.locale); }}
             >
diff --git a/src/components/LocalePicker.js b/src/components/LocalePicker.js
index beb212324eb40595e03bde77284bd7a2e3303636..a1f9d8593dea7ff5e7751ea8e583951859c4f22a 100644
--- a/src/components/LocalePicker.js
+++ b/src/components/LocalePicker.js
@@ -1,9 +1,9 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import MenuItem from '@material-ui/core/MenuItem';
-import FormControl from '@material-ui/core/FormControl';
-import Select from '@material-ui/core/Select';
-import Typography from '@material-ui/core/Typography';
+import MenuItem from '@mui/material/MenuItem';
+import FormControl from '@mui/material/FormControl';
+import Select from '@mui/material/Select';
+import Typography from '@mui/material/Typography';
 
 /**
  * Provide a locale picker
@@ -16,7 +16,6 @@ export class LocalePicker extends Component {
   render() {
     const {
       availableLocales,
-      classes,
       locale,
       setLocale,
     } = this.props;
@@ -30,14 +29,11 @@ export class LocalePicker extends Component {
               horizontal: 'left',
               vertical: 'bottom',
             },
-            getContentAnchorEl: null,
           }}
           displayEmpty
           value={locale}
           onChange={(e) => { setLocale(e.target.value); }}
           name="locale"
-          classes={{ select: classes.select }}
-          className={classes.selectEmpty}
         >
           {
             availableLocales.map(l => (
@@ -52,14 +48,12 @@ export class LocalePicker extends Component {
 
 LocalePicker.propTypes = {
   availableLocales: PropTypes.arrayOf(PropTypes.string),
-  classes: PropTypes.objectOf(PropTypes.string),
   locale: PropTypes.string,
   setLocale: PropTypes.func,
 };
 
 LocalePicker.defaultProps = {
   availableLocales: [],
-  classes: {},
   locale: '',
   setLocale: undefined,
 };
diff --git a/src/components/ManifestForm.js b/src/components/ManifestForm.js
index 18d304cd6dca0f1301e1dd735d812d9135641eb8..2266db77c9df80ab685463034e7e9872117c2868 100644
--- a/src/components/ManifestForm.js
+++ b/src/components/ManifestForm.js
@@ -1,8 +1,8 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Button from '@material-ui/core/Button';
-import Grid from '@material-ui/core/Grid';
-import TextField from '@material-ui/core/TextField';
+import Button from '@mui/material/Button';
+import Grid from '@mui/material/Grid';
+import TextField from '@mui/material/TextField';
 
 /**
  * Provides a form for user input of a manifest url
@@ -68,7 +68,6 @@ export class ManifestForm extends Component {
     const { formValue } = this.state;
     const {
       addResourcesOpen,
-      classes,
       onCancel,
       t,
     } = this.props;
@@ -92,11 +91,19 @@ export class ManifestForm extends Component {
                 shrink: true,
               }}
               InputProps={{
-                className: classes.input,
+                style: { typography: 'body1' },
               }}
             />
           </Grid>
-          <Grid item xs={12} sm={4} md={3} className={classes.buttons}>
+          <Grid
+            item
+            xs={12}
+            sm={4}
+            md={3}
+            sx={{
+              textAlign: { sm: 'inherit', xs: 'right' },
+            }}
+          >
             { onCancel && (
               <Button onClick={this.handleCancel}>
                 {t('cancel')}
@@ -115,14 +122,12 @@ export class ManifestForm extends Component {
 ManifestForm.propTypes = {
   addResource: PropTypes.func.isRequired,
   addResourcesOpen: PropTypes.bool.isRequired,
-  classes: PropTypes.objectOf(PropTypes.string),
   onCancel: PropTypes.func,
   onSubmit: PropTypes.func,
   t: PropTypes.func,
 };
 
 ManifestForm.defaultProps = {
-  classes: {},
   onCancel: null,
   onSubmit: () => {},
   t: key => key,
diff --git a/src/components/ManifestInfo.js b/src/components/ManifestInfo.js
index 4d9b2339257fd314eeae95916a35b6bf71ce453c..e465a054da023abe4245147b934ff4759aef2918 100644
--- a/src/components/ManifestInfo.js
+++ b/src/components/ManifestInfo.js
@@ -1,6 +1,6 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
+import Typography from '@mui/material/Typography';
 import CollapsibleSection from '../containers/CollapsibleSection';
 import SanitizedHtml from '../containers/SanitizedHtml';
 import { LabelValueMetadata } from './LabelValueMetadata';
diff --git a/src/components/ManifestListItem.js b/src/components/ManifestListItem.js
index accd5ede56d5dadcfb6ab8d791359aaeaf838b13..18e26fbc921ecb673c5afc94870e2e7e214ea555 100644
--- a/src/components/ManifestListItem.js
+++ b/src/components/ManifestListItem.js
@@ -1,14 +1,42 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import ListItem from '@material-ui/core/ListItem';
-import ButtonBase from '@material-ui/core/ButtonBase';
-import Grid from '@material-ui/core/Grid';
-import Typography from '@material-ui/core/Typography';
-import Skeleton from '@material-ui/lab/Skeleton';
+import { styled } from '@mui/material/styles';
+import ListItem from '@mui/material/ListItem';
+import ButtonBase from '@mui/material/ButtonBase';
+import Grid from '@mui/material/Grid';
+import Typography from '@mui/material/Typography';
+import Skeleton from '@mui/material/Skeleton';
 import { Img } from 'react-image';
 import ManifestListItemError from '../containers/ManifestListItemError';
 import ns from '../config/css-ns';
 
+const Root = styled(ListItem, { name: 'ManifestListItem', slot: 'root' })(({ ownerState, theme }) => ({
+  '&:hover,&:focus-within': {
+    backgroundColor: theme.palette.action.hover,
+    borderLeftColor: ownerState?.active ? theme.palette.primary.main : theme.palette.action.hover,
+  },
+  borderLeft: '4px solid',
+  borderLeftColor: ownerState?.active ? theme.palette.primary.main : 'transparent',
+  paddingLeft: theme.spacing(2),
+  paddingRight: theme.spacing(2),
+  [theme.breakpoints.up('sm')]: {
+    paddingLeft: theme.spacing(3),
+    paddingRight: theme.spacing(3),
+  },
+}));
+
+const StyledThumbnail = styled(Img, { name: 'ManifestListItem', slot: 'thumbnail' })(({ theme }) => ({
+  maxWidth: '100%',
+  objectFit: 'contain',
+}));
+
+const StyledLogo = styled(Img, { name: 'ManifestListItem', slot: 'logo' })(({ theme }) => ({
+  height: '2.5rem',
+  maxWidth: '100%',
+  objectFit: 'contain',
+  paddingRight: 1,
+}));
+
 /**
  * Represents an item in a list of currently-loaded or loading manifests
  * @param {object} props
@@ -57,7 +85,6 @@ export class ManifestListItem extends Component {
       thumbnail,
       manifestLogo,
       size,
-      classes,
       provider,
       t,
       error,
@@ -68,61 +95,81 @@ export class ManifestListItem extends Component {
     const placeholder = (
       <Grid container className={ns('manifest-list-item')} spacing={2}>
         <Grid item xs={3} sm={2}>
-          <Skeleton className={classes.placeholder} variant="rect" height={80} width={120} />
+          <Skeleton sx={{ bgcolor: 'grey[300]' }} variant="rectangular" height={80} width={120} />
         </Grid>
         <Grid item xs={9} sm={6}>
-          <Skeleton className={classes.placeholder} variant="text" />
+          <Skeleton sx={{ bgcolor: 'grey[300]' }} variant="text" />
         </Grid>
         <Grid item xs={8} sm={2}>
-          <Skeleton className={classes.placeholder} variant="text" />
-          <Skeleton className={classes.placeholder} variant="text" />
+          <Skeleton sx={{ bgcolor: 'grey[300]' }} variant="text" />
+          <Skeleton sx={{ bgcolor: 'grey[300]' }} variant="text" />
         </Grid>
         <Grid item xs={4} sm={2}>
-          <Skeleton className={classes.placeholder} variant="rect" height={60} width={60} />
+          <Skeleton sx={{ bgcolor: 'grey[300]' }} variant="rectangular" height={60} width={60} />
         </Grid>
       </Grid>
     );
 
     if (error) {
       return (
-        <ListItem divider className={classes.root} data-manifestid={manifestId}>
+        <Root
+          ownerState={this.props}
+          divider
+          selected={active}
+          className={active ? 'active' : ''}
+          data-manifestid={manifestId}
+        >
           <ManifestListItemError manifestId={manifestId} />
-        </ListItem>
+        </Root>
       );
     }
 
     return (
-      <ListItem divider className={[classes.root, active ? classes.active : ''].join(' ')} data-manifestid={manifestId}>
+      <Root
+        divider
+        selected={active}
+        className={active ? 'active' : ''}
+        data-manifestid={manifestId}
+        data-active={active}
+      >
         {ready ? (
           <Grid container className={ns('manifest-list-item')} spacing={2}>
-            <Grid item xs={12} sm={6} className={classes.buttonGrid}>
+            <Grid item xs={12} sm={6}>
               <ButtonBase
                 ref={buttonRef}
                 className={ns('manifest-list-item-title')}
                 style={{ width: '100%' }}
                 onClick={this.handleOpenButtonClick}
               >
-                <Grid container spacing={2} className={classes.label} component="span">
+                <Grid
+                  container
+                  spacing={2}
+                  sx={{
+                    textAlign: 'left',
+                    textTransform: 'initial',
+                  }}
+                  component="span"
+                >
                   <Grid item xs={4} sm={3} component="span">
                     { thumbnail
                       ? (
-                        <Img
-                          className={[classes.thumbnail, ns('manifest-list-item-thumb')].join(' ')}
+                        <StyledThumbnail
+                          className={[ns('manifest-list-item-thumb')]}
                           src={[thumbnail]}
                           alt=""
                           height="80"
                           unloader={(
                             <Skeleton
-                              variant="rect"
+                              variant="rectangular"
                               animation={false}
-                              className={classes.placeholder}
+                              sx={{ bgcolor: 'grey[300]' }}
                               height={80}
                               width={120}
                             />
                           )}
                         />
                       )
-                      : <Skeleton className={classes.placeholder} variant="rect" height={80} width={120} />}
+                      : <Skeleton sx={{ bgcolor: 'grey[300]' }} variant="rectangular" height={80} width={120} />}
                   </Grid>
                   <Grid item xs={8} sm={9} component="span">
                     { isCollection && (
@@ -145,16 +192,15 @@ export class ManifestListItem extends Component {
             <Grid item xs={4} sm={2}>
               { manifestLogo
                 && (
-                <Img
+                <StyledLogo
                   src={[manifestLogo]}
                   alt=""
                   role="presentation"
-                  className={classes.logo}
                   unloader={(
                     <Skeleton
-                      variant="rect"
+                      variant="rectangular"
                       animation={false}
-                      className={classes.placeholder}
+                      sx={{ bgcolor: 'grey[300]' }}
                       height={60}
                       width={60}
                     />
@@ -166,7 +212,7 @@ export class ManifestListItem extends Component {
         ) : (
           placeholder
         )}
-      </ListItem>
+      </Root>
     );
   }
 }
@@ -175,7 +221,6 @@ ManifestListItem.propTypes = {
   active: PropTypes.bool,
   addWindow: PropTypes.func.isRequired,
   buttonRef: PropTypes.elementType,
-  classes: PropTypes.objectOf(PropTypes.string),
   error: PropTypes.string,
   fetchManifest: PropTypes.func.isRequired,
   handleClose: PropTypes.func,
@@ -195,7 +240,6 @@ ManifestListItem.propTypes = {
 ManifestListItem.defaultProps = {
   active: false,
   buttonRef: undefined,
-  classes: {},
   error: null,
   handleClose: () => {},
   isCollection: false,
diff --git a/src/components/ManifestListItemError.js b/src/components/ManifestListItemError.js
index 3d63e48afd3445ff3df92814908d91c9ca19a1d2..b8d5176aa5aaa6a967b432f2af601f48fcd67268 100644
--- a/src/components/ManifestListItemError.js
+++ b/src/components/ManifestListItemError.js
@@ -1,9 +1,9 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Button from '@material-ui/core/Button';
-import ErrorIcon from '@material-ui/icons/ErrorOutlineSharp';
-import Grid from '@material-ui/core/Grid';
-import Typography from '@material-ui/core/Typography';
+import Button from '@mui/material/Button';
+import ErrorIcon from '@mui/icons-material/ErrorOutlineSharp';
+import Grid from '@mui/material/Grid';
+import Typography from '@mui/material/Typography';
 
 /**
  * ManifestListItemError renders a component displaying a
@@ -15,7 +15,7 @@ export class ManifestListItemError extends Component {
   */
   render() {
     const {
-      classes, manifestId, onDismissClick, onTryAgainClick, t,
+      manifestId, onDismissClick, onTryAgainClick, t,
     } = this.props;
 
     return (
@@ -24,12 +24,17 @@ export class ManifestListItemError extends Component {
           <Grid container item xs={12} sm={6}>
             <Grid item xs={4} sm={3}>
               <Grid container justifyContent="center">
-                <ErrorIcon className={classes.errorIcon} />
+                <ErrorIcon sx={{
+                  color: 'error.main',
+                  height: '2rem',
+                  width: '2rem',
+                }}
+                />
               </Grid>
             </Grid>
             <Grid item xs={8} sm={9}>
               <Typography>{t('manifestError')}</Typography>
-              <Typography className={classes.manifestIdText}>{manifestId}</Typography>
+              <Typography sx={{ wordBreak: 'break-all' }}>{manifestId}</Typography>
             </Grid>
           </Grid>
         </Grid>
@@ -52,7 +57,6 @@ export class ManifestListItemError extends Component {
 }
 
 ManifestListItemError.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   manifestId: PropTypes.string.isRequired,
   onDismissClick: PropTypes.func.isRequired,
   onTryAgainClick: PropTypes.func.isRequired,
diff --git a/src/components/ManifestRelatedLinks.js b/src/components/ManifestRelatedLinks.js
index 62436ea79a4ba2009ff7ae9cee421a83e1995d40..cbba6aefd1defc8c2a02ab6f68a6b459a27d2ec6 100644
--- a/src/components/ManifestRelatedLinks.js
+++ b/src/components/ManifestRelatedLinks.js
@@ -1,12 +1,19 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
-import Link from '@material-ui/core/Link';
+import { styled } from '@mui/material/styles';
+import Typography from '@mui/material/Typography';
+import Link from '@mui/material/Link';
 import classNames from 'classnames';
 import CollapsibleSection from '../containers/CollapsibleSection';
 import ns from '../config/css-ns';
 import { PluginHook } from './PluginHook';
 
+const StyledDl = styled('dl')(({ theme }) => ({
+  '& dd': {
+    marginBottom: '.5em',
+    marginLeft: '0',
+  },
+}));
 /**
  * ManifestRelatedLinks
  */
@@ -17,7 +24,6 @@ export class ManifestRelatedLinks extends Component {
    */
   render() {
     const {
-      classes,
       homepage,
       manifestUrl,
       related,
@@ -40,7 +46,7 @@ export class ManifestRelatedLinks extends Component {
         >
           {t('links')}
         </Typography>
-        <dl className={classNames(ns('label-value-metadata'), classes.labelValueMetadata)}>
+        <StyledDl className={classNames(ns('label-value-metadata'))}>
           { homepage && (
             <>
               <Typography variant="subtitle2" component="dt">{t('iiif_homepage')}</Typography>
@@ -113,7 +119,7 @@ export class ManifestRelatedLinks extends Component {
               </Typography>
             </>
           )}
-        </dl>
+        </StyledDl>
         <PluginHook {...this.props} />
       </CollapsibleSection>
     );
@@ -121,7 +127,6 @@ export class ManifestRelatedLinks extends Component {
 }
 
 ManifestRelatedLinks.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   homepage: PropTypes.arrayOf(PropTypes.shape({
     label: PropTypes.string,
     value: PropTypes.string,
diff --git a/src/components/MinimalWindow.js b/src/components/MinimalWindow.js
index f19b35385f339bf38761b7d6390e421101833330..b04661692437238242a47ea242933c80c82c0bfe 100644
--- a/src/components/MinimalWindow.js
+++ b/src/components/MinimalWindow.js
@@ -1,15 +1,19 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import MenuIcon from '@material-ui/icons/MenuSharp';
+import { styled } from '@mui/material/styles';
+import MenuIcon from '@mui/icons-material/MenuSharp';
 import cn from 'classnames';
-import Paper from '@material-ui/core/Paper';
-import AppBar from '@material-ui/core/AppBar';
-import Toolbar from '@material-ui/core/Toolbar';
-import Typography from '@material-ui/core/Typography';
-import CloseIcon from '@material-ui/icons/CloseSharp';
+import Paper from '@mui/material/Paper';
+import AppBar from '@mui/material/AppBar';
+import Toolbar from '@mui/material/Toolbar';
+import Typography from '@mui/material/Typography';
+import CloseIcon from '@mui/icons-material/CloseSharp';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 import ns from '../config/css-ns';
 
+const StyledMiradorMenuButton = styled(MiradorMenuButton)(() => ({
+  marginLeft: 'auto',
+}));
 /** */
 export class MinimalWindow extends Component {
   /** */
@@ -19,7 +23,6 @@ export class MinimalWindow extends Component {
       allowWindowSideBar,
       ariaLabel,
       children,
-      classes,
       label,
       removeWindow,
       t,
@@ -32,17 +35,31 @@ export class MinimalWindow extends Component {
         elevation={1}
         id={windowId}
         className={
-          cn(classes.window, ns('placeholder-window'))
+          cn(ns('placeholder-window'))
         }
+        sx={{
+          backgroundColor: 'shades.dark',
+          borderRadius: 0,
+          display: 'flex',
+          flexDirection: 'column',
+          height: '100%',
+          minHeight: 0,
+          overflow: 'hidden',
+          width: '100%',
+        }}
         aria-label={label && ariaLabel ? t('window', { label }) : null}
       >
-        <AppBar position="relative" color="default">
+        <AppBar position="relative" color="default" enableColorOnDark>
           <Toolbar
             disableGutters
-            className={cn(
-              classes.windowTopBarStyle,
-              ns('window-top-bar'),
-            )}
+            className={cn(ns('window-top-bar'))}
+            sx={{
+              backgroundColor: 'shades.main',
+              borderTop: '2px solid transparent',
+              minHeight: 32,
+              paddingLeft: 0.5,
+              paddingRight: 0.5,
+            }}
             variant="dense"
           >
             {allowWindowSideBar && (
@@ -53,20 +70,29 @@ export class MinimalWindow extends Component {
                 <MenuIcon />
               </MiradorMenuButton>
             )}
-            <Typography variant="h2" noWrap color="inherit" className={classes.title}>
+            <Typography
+              variant="h2"
+              noWrap
+              color="inherit"
+              sx={{
+                flexGrow: 1,
+                paddingLeft: 0.5,
+                typography: 'h6',
+              }}
+            >
               {label}
             </Typography>
             {allowClose && removeWindow && (
-              <MiradorMenuButton
+              <StyledMiradorMenuButton
                 aria-label={t('closeWindow')}
-                className={cn(classes.button, ns('window-close'))}
+                className={cn(ns('window-close'))}
                 onClick={removeWindow}
                 TooltipProps={{
-                  tabIndex: ariaLabel ? '0' : '-1',
+                  tabIndex: ariaLabel ? 0 : -1,
                 }}
               >
                 <CloseIcon />
-              </MiradorMenuButton>
+              </StyledMiradorMenuButton>
             )}
           </Toolbar>
         </AppBar>
@@ -81,7 +107,6 @@ MinimalWindow.propTypes = {
   allowWindowSideBar: PropTypes.bool,
   ariaLabel: PropTypes.bool,
   children: PropTypes.node,
-  classes: PropTypes.objectOf(PropTypes.string),
   label: PropTypes.string,
   removeWindow: PropTypes.func,
   t: PropTypes.func,
@@ -93,7 +118,6 @@ MinimalWindow.defaultProps = {
   allowWindowSideBar: true,
   ariaLabel: true,
   children: null,
-  classes: {},
   label: '',
   removeWindow: () => {},
   t: key => key,
diff --git a/src/components/MiradorMenuButton.js b/src/components/MiradorMenuButton.js
index 869c1c0a024b9c54df2960d9698da1be2e47d535..e1def5a7b87b9283121bacf3e8a85e04da4e6b2f 100644
--- a/src/components/MiradorMenuButton.js
+++ b/src/components/MiradorMenuButton.js
@@ -1,7 +1,15 @@
 import PropTypes from 'prop-types';
-import Badge from '@material-ui/core/Badge';
-import IconButton from '@material-ui/core/IconButton';
-import Tooltip from '@material-ui/core/Tooltip';
+import { styled } from '@mui/material/styles';
+import Badge from '@mui/material/Badge';
+import IconButton from '@mui/material/IconButton';
+import Tooltip from '@mui/material/Tooltip';
+
+const Root = styled(IconButton, { name: 'MiradorMenuButton', slot: 'root' })(({ ownerState, theme }) => ({
+  fill: 'currentcolor',
+  ...(ownerState.selected && {
+    backgroundColor: theme.palette.action.selected,
+  }),
+}));
 
 /**
  * MiradorMenuButton ~ Wrap the given icon prop in an IconButton and a Tooltip.
@@ -17,15 +25,28 @@ export function MiradorMenuButton(props) {
     dispatch,
     BadgeProps,
     TooltipProps,
+    sx,
     ...iconButtonProps
   } = props;
 
   const button = (
-    <IconButton {...iconButtonProps}>
+    <Root
+      ownerState={props}
+      {...iconButtonProps}
+      sx={sx}
+      size="large"
+    >
       {badge
-        ? <Badge overlap="rectangular" {...BadgeProps}>{children}</Badge>
+        ? (
+          <Badge
+            overlap="rectangular"
+            {...BadgeProps}
+          >
+            {children}
+          </Badge>
+        )
         : children}
-    </IconButton>
+    </Root>
   );
 
   if (iconButtonProps.disabled) return button;
@@ -50,6 +71,8 @@ MiradorMenuButton.propTypes = {
   children: PropTypes.element.isRequired,
   container: PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
   dispatch: PropTypes.func,
+  selected: PropTypes.bool,
+  sx: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   TooltipProps: PropTypes.object, // eslint-disable-line react/forbid-prop-types
 };
 
@@ -58,5 +81,7 @@ MiradorMenuButton.defaultProps = {
   BadgeProps: {},
   container: null,
   dispatch: () => {},
+  selected: false,
+  sx: {},
   TooltipProps: {},
 };
diff --git a/src/components/NestedMenu.js b/src/components/NestedMenu.js
index 65fcfeec57a1d7681510747b3dc3bb120358d57f..b61107786453d1b98aff1749f704089d9e686e10 100644
--- a/src/components/NestedMenu.js
+++ b/src/components/NestedMenu.js
@@ -1,10 +1,10 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import ListItemIcon from '@material-ui/core/ListItemIcon';
-import ListItemText from '@material-ui/core/ListItemText';
-import MenuItem from '@material-ui/core/MenuItem';
-import ExpandLess from '@material-ui/icons/ExpandLessSharp';
-import ExpandMore from '@material-ui/icons/ExpandMoreSharp';
+import ListItemIcon from '@mui/material/ListItemIcon';
+import ListItemText from '@mui/material/ListItemText';
+import MenuItem from '@mui/material/MenuItem';
+import ExpandLess from '@mui/icons-material/ExpandLessSharp';
+import ExpandMore from '@mui/icons-material/ExpandMoreSharp';
 
 /**
  * NestedMenu ~ A presentation component to render a menu item and have
diff --git a/src/components/OpenSeadragonViewer.js b/src/components/OpenSeadragonViewer.js
index f2ce17d670a9b5b5d7c0586fc8bda242fdc92b67..120aba5151fee7995e5985902cf3e8cf8bcdcc84 100644
--- a/src/components/OpenSeadragonViewer.js
+++ b/src/components/OpenSeadragonViewer.js
@@ -2,6 +2,7 @@ import {
   createRef, Children, cloneElement, Component,
 } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import debounce from 'lodash/debounce';
 import isEqual from 'lodash/isEqual';
 import OpenSeadragon from 'openseadragon';
@@ -12,6 +13,11 @@ import CanvasWorld from '../lib/CanvasWorld';
 import { PluginHook } from './PluginHook';
 import { OSDReferences } from '../plugins/OSDReferences';
 
+const StyledSection = styled('section')({
+  cursor: 'grab',
+  flex: 1,
+  position: 'relative',
+});
 /**
  * Represents a OpenSeadragonViewer in the mirador workspace. Responsible for mounting
  * and rendering OSD.
@@ -340,7 +346,7 @@ export class OpenSeadragonViewer extends Component {
    */
   render() {
     const {
-      children, classes, label, t, windowId,
+      children, label, t, windowId,
       drawAnnotations,
     } = this.props;
     const { viewer, grabbing } = this.state;
@@ -355,8 +361,8 @@ export class OpenSeadragonViewer extends Component {
     ));
 
     return (
-      <section
-        className={classNames(ns('osd-container'), classes.osdContainer)}
+      <StyledSection
+        className={classNames(ns('osd-container'))}
         style={{ cursor: grabbing ? 'grabbing' : undefined }}
         id={`${windowId}-osd`}
         ref={this.ref}
@@ -367,7 +373,7 @@ export class OpenSeadragonViewer extends Component {
             && <AnnotationsOverlay viewer={viewer} windowId={windowId} /> }
         { enhancedChildren }
         <PluginHook viewer={viewer} {...{ ...this.props, children: null }} />
-      </section>
+      </StyledSection>
     );
   }
 }
@@ -385,7 +391,6 @@ OpenSeadragonViewer.defaultProps = {
 OpenSeadragonViewer.propTypes = {
   canvasWorld: PropTypes.instanceOf(CanvasWorld).isRequired,
   children: PropTypes.node,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   drawAnnotations: PropTypes.bool,
   infoResponses: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types
   label: PropTypes.string,
diff --git a/src/components/PrimaryWindow.js b/src/components/PrimaryWindow.js
index 988b6784aea40a2167782f35ea06cc8964e10851..30c4d302eb4e9794fc9c9b73e318c02a24e78982 100644
--- a/src/components/PrimaryWindow.js
+++ b/src/components/PrimaryWindow.js
@@ -1,5 +1,6 @@
 import { Component, lazy, Suspense } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import classNames from 'classnames';
 import WindowSideBar from '../containers/WindowSideBar';
 import CompanionArea from '../containers/CompanionArea';
@@ -16,6 +17,12 @@ GalleryView.displayName = 'GalleryView';
 SelectCollection.displayName = 'SelectCollection';
 WindowViewer.displayName = 'WindowViewer';
 
+const Root = styled('div', { name: 'PrimaryWindow', slot: 'root' })(() => ({
+  display: 'flex',
+  flex: 1,
+  position: 'relative',
+}));
+
 /**
  * PrimaryWindow - component that renders the primary content of a Mirador
  * window. Right now this differentiates between a Image, Video, or Audio viewer.
@@ -74,17 +81,18 @@ export class PrimaryWindow extends Component {
    */
   render() {
     const {
-      isCollectionDialogVisible, windowId, classes, children,
+      isCollectionDialogVisible, windowId, children, className,
     } = this.props;
+
     return (
-      <div className={classNames(ns('primary-window'), classes.primaryWindow)}>
+      <Root data-testid="test-window" className={classNames(ns('primary-window'), className)}>
         <WindowSideBar windowId={windowId} />
         <CompanionArea windowId={windowId} position="left" />
         { isCollectionDialogVisible && <CollectionDialog windowId={windowId} /> }
         <Suspense fallback={<div />}>
           {children || this.renderViewer()}
         </Suspense>
-      </div>
+      </Root>
     );
   }
 }
@@ -92,7 +100,7 @@ export class PrimaryWindow extends Component {
 PrimaryWindow.propTypes = {
   audioResources: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types
   children: PropTypes.node,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
+  className: PropTypes.string,
   isCollection: PropTypes.bool,
   isCollectionDialogVisible: PropTypes.bool,
   isFetching: PropTypes.bool,
@@ -104,6 +112,7 @@ PrimaryWindow.propTypes = {
 PrimaryWindow.defaultProps = {
   audioResources: [],
   children: undefined,
+  className: undefined,
   isCollection: false,
   isCollectionDialogVisible: false,
   isFetching: false,
diff --git a/src/components/SanitizedHtml.js b/src/components/SanitizedHtml.js
index 1cd1f4b24f8e66ba51301bcf4776b116327d2a44..dcbab42e3b20ca80f030dd607c9f5639d4658cb3 100644
--- a/src/components/SanitizedHtml.js
+++ b/src/components/SanitizedHtml.js
@@ -1,9 +1,12 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import DOMPurify from 'dompurify';
 import ns from '../config/css-ns';
 import htmlRules from '../lib/htmlRules';
 
+const Root = styled('span', { name: 'IIIFHtmlContent', slot: 'root' })({});
+
 /**
 */
 export class SanitizedHtml extends Component {
@@ -25,8 +28,8 @@ export class SanitizedHtml extends Component {
     });
 
     return (
-      <span
-        className={[classes.root, ns('third-party-html')].join(' ')}
+      <Root
+        className={[ns('third-party-html'), classes.root].join(' ')}
         dangerouslySetInnerHTML={{ // eslint-disable-line react/no-danger
           __html: DOMPurify.sanitize(htmlString, htmlRules[ruleSet]),
         }}
diff --git a/src/components/ScrollIndicatedDialogContent.js b/src/components/ScrollIndicatedDialogContent.js
index a8de5229d8d8e09e70aa881432246ccb568c5fc3..01e10ca255355b32e255b4f3380d0bfa6e814fb5 100644
--- a/src/components/ScrollIndicatedDialogContent.js
+++ b/src/components/ScrollIndicatedDialogContent.js
@@ -1,5 +1,49 @@
 import PropTypes from 'prop-types';
-import DialogContent from '@material-ui/core/DialogContent';
+import DialogContent from '@mui/material/DialogContent';
+import { alpha, styled } from '@mui/material/styles';
+
+/**
+ * From https://github.com/mui/material-ui/blob/v5.15.0/packages/mui-material/src/styles/getOverlayAlpha.ts
+ */
+const getOverlayAlpha = (elevation) => {
+  let alphaValue;
+  if (elevation < 1) {
+    alphaValue = 5.11916 * elevation ** 2;
+  } else {
+    alphaValue = 4.5 * Math.log(elevation + 1) + 2;
+  }
+  return (alphaValue / 100).toFixed(2);
+};
+
+const Root = styled(DialogContent, { name: 'ScrollIndicatedDialogContent', slot: 'root' })(({ ownerState, theme }) => {
+  // In dark mode, paper has a elevation-dependent background color:
+  // https://github.com/mui/material-ui/blob/v5.15.0/packages/mui-material/src/Paper/Paper.js#L55-L60
+  const bgcolor = theme.palette.mode === 'dark' ? {
+    backgroundImage: `linear-gradient(${alpha(
+      '#fff',
+      getOverlayAlpha(ownerState?.elevation || 24),
+    )}, ${alpha('#fff', getOverlayAlpha(ownerState?.elevation || 24))})`,
+  } : theme.palette.background.paper;
+  return {
+    /* Shadow covers */
+    background: `linear-gradient(${bgcolor} 30%, rgba(255, 255, 255, 0)), `
+      + `linear-gradient(rgba(255, 255, 255, 0), ${bgcolor} 70%) 0 100%, `
+      // Shaddows
+      + 'radial-gradient(50% 0, farthest-side, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)), '
+      + 'radial-gradient(50% 100%, farthest-side, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) 0 100%,',
+    /* Shadow covers */
+    background: `linear-gradient(${bgcolor} 30%, rgba(255, 255, 255, 0)), ` // eslint-disable-line no-dupe-keys
+      + `linear-gradient(rgba(255, 255, 255, 0), ${bgcolor} 70%) 0 100%, `
+      // Shaddows
+      + 'radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)), '
+      + 'radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) 0 100%;',
+
+    backgroundAttachment: 'local, local, scroll, scroll',
+    backgroundRepeat: 'no-repeat',
+    backgroundSize: '100% 40px, 100% 40px, 100% 14px, 100% 14px',
+    overflowY: 'auto',
+  };
+});
 
 /**
  * ScrollIndicatedDialogContent ~ Inject a style into the DialogContent component
@@ -10,18 +54,21 @@ export function ScrollIndicatedDialogContent(props) {
   const ourClassName = [className, classes.shadowScrollDialog].join(' ');
 
   return (
-    <DialogContent className={ourClassName} {...otherProps} />
+    <Root
+      className={ourClassName}
+      {...otherProps}
+    />
   );
 }
 
 ScrollIndicatedDialogContent.propTypes = {
   classes: PropTypes.shape({
     shadowScrollDialog: PropTypes.string,
-  }).isRequired,
-
+  }),
   className: PropTypes.string,
 };
 
 ScrollIndicatedDialogContent.defaultProps = {
+  classes: {},
   className: '',
 };
diff --git a/src/components/ScrollTo.js b/src/components/ScrollTo.js
index e73d602cf998bf9d9adcdc17d6b730c4b91406f5..4e11892d7267729ba6619f090c407910785d3612 100644
--- a/src/components/ScrollTo.js
+++ b/src/components/ScrollTo.js
@@ -1,5 +1,6 @@
-import { createRef, Component } from 'react';
+import { cloneElement, createRef, Component } from 'react';
 import PropTypes from 'prop-types';
+import isEmpty from 'lodash/isEmpty';
 
 /**
  * ScrollTo ~
@@ -36,9 +37,9 @@ export class ScrollTo extends Component {
   containerBoundingRect() {
     const { containerRef } = this.props;
 
-    if (!containerRef || !containerRef.current || !containerRef.current.domEl) return {};
+    if (!containerRef || !containerRef.current) return {};
 
-    return containerRef.current.domEl.getBoundingClientRect();
+    return containerRef.current.getBoundingClientRect();
   }
 
   /**
@@ -59,14 +60,14 @@ export class ScrollTo extends Component {
   }
 
   /**
-   * The container provided in the containersRef dome structure in which scrolling
+   * The container provided in the containersRef dom structure in which scrolling
    * should happen.
   */
   scrollableContainer() {
     const { containerRef } = this.props;
 
-    if (!containerRef || !containerRef.current || !containerRef.current.domEl) return null;
-    return containerRef.current.domEl.getElementsByClassName('mirador-scrollto-scrollable')[0];
+    if (!containerRef || !containerRef.current) return null;
+    return containerRef.current.getElementsByClassName('mirador-scrollto-scrollable')[0];
   }
 
   /**
@@ -104,16 +105,12 @@ export class ScrollTo extends Component {
   */
   render() {
     const {
-      children, containerRef, offsetTop, scrollTo, ...otherProps
+      children, containerRef, offsetTop, scrollTo, nodeId, ...otherProps
     } = this.props;
 
-    if (!scrollTo) return children;
+    if (!scrollTo && isEmpty(otherProps)) return children;
 
-    return (
-      <div ref={this.scrollToRef} {...otherProps}>
-        {children}
-      </div>
-    );
+    return cloneElement(children, { ref: this.scrollToRef, ...otherProps });
   }
 }
 
@@ -123,6 +120,7 @@ ScrollTo.propTypes = {
     PropTypes.func,
     PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
   ]).isRequired,
+  nodeId: PropTypes.string.isRequired,
   offsetTop: PropTypes.number,
   scrollTo: PropTypes.bool.isRequired,
 };
diff --git a/src/components/SearchHit.js b/src/components/SearchHit.js
index 6314f2f6add3f3ad81cb003bbb345d91b18f1116..41a8be606d62b03431e3b9c2a283a8591a8a9b1c 100644
--- a/src/components/SearchHit.js
+++ b/src/components/SearchHit.js
@@ -1,15 +1,49 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import clsx from 'clsx';
-import Button from '@material-ui/core/Button';
-import ListItem from '@material-ui/core/ListItem';
-import ListItemText from '@material-ui/core/ListItemText';
-import Typography from '@material-ui/core/Typography';
-import Chip from '@material-ui/core/Chip';
+import Button from '@mui/material/Button';
+import ListItem from '@mui/material/ListItem';
+import ListItemText from '@mui/material/ListItemText';
+import Typography from '@mui/material/Typography';
+import Chip from '@mui/material/Chip';
+import { styled } from '@mui/material/styles';
 import SanitizedHtml from '../containers/SanitizedHtml';
 import TruncatedHit from '../lib/TruncatedHit';
 import { ScrollTo } from './ScrollTo';
 
+const Root = styled(ListItem, { name: 'SearchHit', slot: 'root' })(({ ownerState, theme }) => ({
+  '&.Mui-focused': {
+    '&:hover': {
+      ...(ownerState.windowSelected && {
+        backgroundColor: 'inherit',
+      }),
+    },
+    ...(ownerState.windowSelected && {
+      backgroundColor: 'inherit',
+    }),
+  },
+  paddingRight: theme.spacing(1),
+}));
+
+const CanvasLabel = styled('h4', { name: 'SearchHit', slot: 'canvasLabel' })(({ theme }) => ({
+  display: 'inline',
+  marginBottom: theme.spacing(1.5),
+}));
+
+const Counter = styled(Chip, { name: 'SearchHit', slot: 'counter' })(({ ownerState, theme }) => ({
+  // eslint-disable-next-line no-nested-ternary
+  backgroundColor: theme.palette.hitCounter.default,
+  ...(ownerState.windowSelected && {
+    backgroundColor: theme.palette.highlights.primary,
+  }),
+  ...(ownerState.adjacent && !ownerState.windowSelected && {
+    backgroundColor: theme.palette.highlights.secondary,
+  }),
+  height: 30,
+  marginRight: theme.spacing(1),
+  typography: 'subtitle2',
+  verticalAlign: 'inherit',
+}));
+
 /** */
 export class SearchHit extends Component {
   /** */
@@ -78,7 +112,6 @@ export class SearchHit extends Component {
       annotation,
       annotationLabel,
       canvasLabel,
-      classes,
       companionWindowId,
       containerRef,
       hit,
@@ -95,6 +128,25 @@ export class SearchHit extends Component {
     const truncatedHit = focused ? hit : hit && new TruncatedHit(hit, annotation);
     const truncated = hit && (truncatedHit.before !== hit.before || truncatedHit.after !== hit.after);
     const canvasLabelHtmlId = `${companionWindowId}-${index}`;
+    const ownerState = {
+      adjacent, focused, selected, windowSelected,
+    };
+
+    const header = (
+      <>
+        <Counter
+          component="span"
+          ownerState={ownerState}
+          label={index + 1}
+        />
+        <CanvasLabel id={canvasLabelHtmlId}>
+          {canvasLabel}
+          {annotationLabel && (
+            <Typography component="span" sx={{ display: 'block', marginTop: 1 }}>{annotationLabel}</Typography>
+          )}
+        </CanvasLabel>
+      </>
+    );
 
     return (
       <ScrollTo
@@ -102,51 +154,56 @@ export class SearchHit extends Component {
         offsetTop={96} // offset for the height of the form above
         scrollTo={windowSelected && !focused}
       >
-        <ListItem
-          className={clsx(
-            classes.listItem,
-            {
-              [classes.adjacent]: adjacent,
-              [classes.selected]: selected,
-              [classes.focused]: focused,
-              [classes.windowSelected]: windowSelected,
-            },
-          )}
+        <Root
+          ownerState={ownerState}
+          className={windowSelected ? 'windowSelected' : ''}
+          divider
           button={!selected}
           component="li"
           onClick={this.handleClick}
           selected={selected}
         >
-          <ListItemText primaryTypographyProps={{ variant: 'body1' }}>
-            <Typography variant="subtitle2" className={classes.subtitle}>
-              <Chip component="span" label={index + 1} className={classes.hitCounter} />
-              <span id={canvasLabelHtmlId}>
-                {canvasLabel}
-              </span>
-            </Typography>
-            {annotationLabel && (
-              <Typography variant="subtitle2">{annotationLabel}</Typography>
-            )}
-            {hit && (
+          <ListItemText
+            primary={header}
+            primaryTypographyProps={{ component: 'div', sx: { marginBottom: 1 }, variant: 'subtitle2' }}
+            secondaryTypographyProps={{ variant: 'body1' }}
+            secondary={(
               <>
-                <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.before} />
-                {' '}
-                <strong>
-                  <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.match} />
-                </strong>
-                {' '}
-                <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.after} />
-                {' '}
-                { truncated && !focused && (
-                  <Button className={classes.inlineButton} onClick={showDetails} color="secondary" size="small" aria-describedby={canvasLabelHtmlId}>
-                    {t('more')}
-                  </Button>
+                {hit && (
+                  <>
+                    <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.before} />
+                    {' '}
+                    <strong>
+                      <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.match} />
+                    </strong>
+                    {' '}
+                    <SanitizedHtml ruleSet="iiif" htmlString={truncatedHit.after} />
+                    {' '}
+                    {truncated && !focused && (
+                      <Button
+                        sx={{
+                          '& span': {
+                            lineHeight: '1.5em',
+                          },
+                          margin: 0,
+                          padding: 0,
+                          textTransform: 'none',
+                        }}
+                        onClick={showDetails}
+                        color="secondary"
+                        size="small"
+                        aria-describedby={canvasLabelHtmlId}
+                      >
+                        {t('more')}
+                      </Button>
+                    )}
+                  </>
                 )}
+                {!hit && annotation && <SanitizedHtml ruleSet="iiif" htmlString={annotation.chars} />}
               </>
             )}
-            {!hit && annotation && <SanitizedHtml ruleSet="iiif" htmlString={annotation.chars} />}
-          </ListItemText>
-        </ListItem>
+          />
+        </Root>
       </ScrollTo>
     );
   }
@@ -162,7 +219,6 @@ SearchHit.propTypes = {
   annotationLabel: PropTypes.string,
   announcer: PropTypes.func,
   canvasLabel: PropTypes.string,
-  classes: PropTypes.objectOf(PropTypes.string),
   companionWindowId: PropTypes.string,
   containerRef: PropTypes.oneOfType([
     PropTypes.func,
@@ -191,7 +247,6 @@ SearchHit.defaultProps = {
   annotationLabel: undefined,
   announcer: undefined,
   canvasLabel: undefined,
-  classes: {},
   companionWindowId: undefined,
   containerRef: undefined,
   focused: false,
diff --git a/src/components/SearchPanel.js b/src/components/SearchPanel.js
index 68063764646d16ba6669f11b6464736063b91d2f..42550dddf38e39fe4681302927f4ad07b09a379b 100644
--- a/src/components/SearchPanel.js
+++ b/src/components/SearchPanel.js
@@ -1,8 +1,8 @@
 import { createRef, Component } from 'react';
 import PropTypes from 'prop-types';
-import Button from '@material-ui/core/Button';
-import Chip from '@material-ui/core/Chip';
-import Typography from '@material-ui/core/Typography';
+import Button from '@mui/material/Button';
+import Chip from '@mui/material/Chip';
+import Typography from '@mui/material/Typography';
 import CompanionWindow from '../containers/CompanionWindow';
 import SearchPanelControls from '../containers/SearchPanelControls';
 import SearchResults from '../containers/SearchResults';
@@ -19,7 +19,6 @@ export class SearchPanel extends Component {
   /** */
   render() {
     const {
-      classes,
       fetchSearch,
       windowId,
       id,
@@ -40,7 +39,7 @@ export class SearchPanel extends Component {
               query && query !== '' && (
                 <Chip
                   role="button"
-                  className={classes.clearChip}
+                  sx={{ marginLeft: 1 }}
                   color="secondary"
                   label={t('clearSearch')}
                   onClick={removeSearch}
@@ -65,8 +64,12 @@ export class SearchPanel extends Component {
         />
         {
           fetchSearch && suggestedSearches && query === '' && suggestedSearches.map(search => (
-            <Typography component="p" key={search} variant="body1">
-              <Button className={classes.inlineButton} color="secondary" onClick={() => fetchSearch(`${searchService.id}?q=${search}`, search)}>
+            <Typography component="p" key={search} variant="body1" sx={{ margin: 2 }}>
+              <Button
+                variant="inlineText"
+                color="secondary"
+                onClick={() => fetchSearch(`${searchService.id}?q=${search}`, search)}
+              >
                 {t('suggestSearch', { query: search })}
               </Button>
             </Typography>
@@ -78,10 +81,6 @@ export class SearchPanel extends Component {
 }
 
 SearchPanel.propTypes = {
-  classes: PropTypes.shape({
-    clearChip: PropTypes.string,
-    inlineButton: PropTypes.string,
-  }),
   fetchSearch: PropTypes.func,
   id: PropTypes.string.isRequired,
   query: PropTypes.string,
@@ -95,7 +94,6 @@ SearchPanel.propTypes = {
 };
 
 SearchPanel.defaultProps = {
-  classes: {},
   fetchSearch: undefined,
   query: '',
   suggestedSearches: [],
diff --git a/src/components/SearchPanelControls.js b/src/components/SearchPanelControls.js
index f16939757a6831f843b1dfd7bcb2d470fb63d4ef..0ebdc7185a243bf533c1263525b3e5dd39996f07 100644
--- a/src/components/SearchPanelControls.js
+++ b/src/components/SearchPanelControls.js
@@ -1,15 +1,23 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import deburr from 'lodash/deburr';
 import debounce from 'lodash/debounce';
 import isObject from 'lodash/isObject';
-import Autocomplete from '@material-ui/lab/Autocomplete';
-import CircularProgress from '@material-ui/core/CircularProgress';
-import TextField from '@material-ui/core/TextField';
-import SearchIcon from '@material-ui/icons/SearchSharp';
+import Autocomplete from '@mui/material/Autocomplete';
+import CircularProgress from '@mui/material/CircularProgress';
+import TextField from '@mui/material/TextField';
+import InputAdornment from '@mui/material/InputAdornment';
+import SearchIcon from '@mui/icons-material/SearchSharp';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 import SearchPanelNavigation from '../containers/SearchPanelNavigation';
 
+const StyledForm = styled('form', { name: 'SearchPanelControls', slot: 'form' })(({ theme }) => ({
+  paddingBottom: theme.spacing(1),
+  paddingRight: theme.spacing(1.5),
+  width: '100%',
+}));
+
 /** Sometimes an autocomplete match can be a simple string, other times an object
     with a `match` property, this function abstracts that away */
 const getMatch = (option) => (isObject(option) ? option.match : option);
@@ -117,48 +125,62 @@ export class SearchPanelControls extends Component {
   /** */
   render() {
     const {
-      classes, companionWindowId, searchIsFetching, t, windowId,
+      companionWindowId, searchIsFetching, t, windowId,
     } = this.props;
 
     const { search, suggestions } = this.state;
     const id = `search-${companionWindowId}`;
     return (
       <>
-        <form aria-label={t('searchTitle')} onSubmit={this.submitSearch} className={classes.form}>
+        <StyledForm
+          aria-label={t('searchTitle')}
+          onSubmit={this.submitSearch}
+        >
           <Autocomplete
             id={id}
             inputValue={search}
             options={suggestions}
             getOptionLabel={getMatch}
-            getOptionSelected={(option, value) => (
+            isOptionEqualToValue={(option, value) => (
               deburr(getMatch(option).trim()).toLowerCase()
-                === deburr(getMatch(value).trim()).toLowerCase()
+              === deburr(getMatch(value).trim()).toLowerCase()
             )}
             noOptionsText=""
             onChange={this.selectItem}
             onInputChange={this.handleChange}
             freeSolo
+            disableClearable
             renderInput={params => (
               <TextField
                 {...params}
                 label={t('searchInputLabel')}
+                variant="standard"
                 InputProps={{
                   ...params.InputProps,
                   endAdornment: (
-                    <div className={classes.endAdornment}>
+                    <InputAdornment sx={{ position: 'relative' }} position="end">
                       <MiradorMenuButton aria-label={t('searchSubmitAria')} type="submit">
                         <SearchIcon />
                       </MiradorMenuButton>
                       {Boolean(searchIsFetching) && (
-                        <CircularProgress className={classes.searchProgress} size={50} />
+                      <CircularProgress
+                        sx={{
+                          left: '50%',
+                          marginLeft: '-25px',
+                          marginTop: '-25px',
+                          position: 'absolute',
+                          top: '50%',
+                        }}
+                        size={50}
+                      />
                       )}
-                    </div>
+                    </InputAdornment>
                   ),
                 }}
               />
             )}
           />
-        </form>
+        </StyledForm>
         <SearchPanelNavigation windowId={windowId} companionWindowId={companionWindowId} />
       </>
     );
@@ -169,7 +191,6 @@ SearchPanelControls.propTypes = {
   autocompleteService: PropTypes.shape({
     id: PropTypes.string,
   }),
-  classes: PropTypes.objectOf(PropTypes.string),
   companionWindowId: PropTypes.string.isRequired,
   fetchSearch: PropTypes.func.isRequired,
   query: PropTypes.string,
@@ -183,7 +204,6 @@ SearchPanelControls.propTypes = {
 
 SearchPanelControls.defaultProps = {
   autocompleteService: undefined,
-  classes: {},
   query: '',
   t: key => key,
 };
diff --git a/src/components/SearchPanelNavigation.js b/src/components/SearchPanelNavigation.js
index 72eb84e1fe181a6756d8a32644721fe28e4f7b40..3ddf2c49b5dc8631e09c7002aef30ef731c3f9e9 100644
--- a/src/components/SearchPanelNavigation.js
+++ b/src/components/SearchPanelNavigation.js
@@ -1,8 +1,8 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import ChevronLeftIcon from '@material-ui/icons/ChevronLeftSharp';
-import ChevronRightIcon from '@material-ui/icons/ChevronRightSharp';
-import Typography from '@material-ui/core/Typography';
+import ChevronLeftIcon from '@mui/icons-material/ChevronLeftSharp';
+import ChevronRightIcon from '@mui/icons-material/ChevronRightSharp';
+import Typography from '@mui/material/Typography';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 
 /**
@@ -42,7 +42,7 @@ export class SearchPanelNavigation extends Component {
   */
   render() {
     const {
-      numTotal, searchHits, selectedContentSearchAnnotation, classes, t, direction,
+      numTotal, searchHits, selectedContentSearchAnnotation, t, direction,
     } = this.props;
 
     const iconStyle = direction === 'rtl' ? { transform: 'rotate(180deg)' } : {};
@@ -57,7 +57,7 @@ export class SearchPanelNavigation extends Component {
     if (searchHits.length === 0) return null;
 
     return (
-      <Typography variant="body2" align="center" classes={classes}>
+      <Typography variant="body2" align="center">
         <MiradorMenuButton
           aria-label={t('searchPreviousResult')}
           disabled={!this.hasPreviousResult(currentHitIndex)}
@@ -80,7 +80,6 @@ export class SearchPanelNavigation extends Component {
   }
 }
 SearchPanelNavigation.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string),
   direction: PropTypes.string.isRequired,
   numTotal: PropTypes.number,
   searchHits: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types
@@ -93,7 +92,6 @@ SearchPanelNavigation.propTypes = {
   windowId: PropTypes.string.isRequired, // eslint-disable-line react/no-unused-prop-types
 };
 SearchPanelNavigation.defaultProps = {
-  classes: {},
   numTotal: undefined,
   searchHits: [],
   t: key => key,
diff --git a/src/components/SearchResults.js b/src/components/SearchResults.js
index c38e5c082a2f858ccce60237ddbd1a50c0384a2e..15263db3badcdef2e994cbd17f78073eb9c2c673 100644
--- a/src/components/SearchResults.js
+++ b/src/components/SearchResults.js
@@ -1,9 +1,9 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Button from '@material-ui/core/Button';
-import List from '@material-ui/core/List';
-import Typography from '@material-ui/core/Typography';
-import BackIcon from '@material-ui/icons/ArrowBackSharp';
+import Button from '@mui/material/Button';
+import List from '@mui/material/List';
+import Typography from '@mui/material/Typography';
+import BackIcon from '@mui/icons-material/ArrowBackSharp';
 import { announce } from '@react-aria/live-announcer';
 import SearchHit from '../containers/SearchHit';
 import { ScrollTo } from './ScrollTo';
@@ -80,7 +80,6 @@ export class SearchResults extends Component {
   /** */
   render() {
     const {
-      classes,
       companionWindowId,
       containerRef,
       isFetching,
@@ -106,14 +105,18 @@ export class SearchResults extends Component {
       <>
         { focused && (
           <ScrollTo containerRef={containerRef} offsetTop={96} scrollTo>
-            <Button onClick={this.toggleFocus} className={classes.navigation} size="small">
+            <Button onClick={this.toggleFocus} sx={{ textTransform: 'none' }} size="small">
               <BackIcon />
               {t('backToResults')}
             </Button>
           </ScrollTo>
         )}
         {noResultsState && (
-          <Typography className={classes.noResults}>
+          <Typography sx={{
+            padding: 2,
+            typography: 'h6',
+          }}
+          >
             {t('searchNoResults')}
           </Typography>
         )}
@@ -122,7 +125,7 @@ export class SearchResults extends Component {
         </List>
         { nextSearch && (
           <Button
-            className={classes.moreButton}
+            sx={{ width: '100%' }}
             color="secondary"
             onClick={() => fetchSearch(windowId, companionWindowId, nextSearch, query)}
           >
@@ -137,7 +140,6 @@ export class SearchResults extends Component {
 }
 
 SearchResults.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string),
   companionWindowId: PropTypes.string.isRequired,
   containerRef: PropTypes.oneOfType([
     PropTypes.func,
@@ -155,7 +157,6 @@ SearchResults.propTypes = {
 };
 
 SearchResults.defaultProps = {
-  classes: {},
   containerRef: undefined,
   isFetching: false,
   nextSearch: undefined,
diff --git a/src/components/SelectCollection.js b/src/components/SelectCollection.js
index cc7531393381731a4d8ff87ffc2684e4701d49f3..c51af8f531c25e41baf455a1eacb260a42eae8c2 100644
--- a/src/components/SelectCollection.js
+++ b/src/components/SelectCollection.js
@@ -1,9 +1,9 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Button from '@material-ui/core/Button';
-import Grid from '@material-ui/core/Grid';
-import Typography from '@material-ui/core/Typography';
-import ListSharpIcon from '@material-ui/icons/ListSharp';
+import Button from '@mui/material/Button';
+import Grid from '@mui/material/Grid';
+import Typography from '@mui/material/Typography';
+import ListSharpIcon from '@mui/icons-material/ListSharp';
 
 /**
  *
diff --git a/src/components/SidebarIndexItem.js b/src/components/SidebarIndexItem.js
index d6b1a96668006e072062bd0cd0b1b0d0d1f9dc4e..11bb4af9c08171d10ee6a9a8be4c059a3a7711b1 100644
--- a/src/components/SidebarIndexItem.js
+++ b/src/components/SidebarIndexItem.js
@@ -1,19 +1,17 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
-import classNames from 'classnames';
+import Typography from '@mui/material/Typography';
 
 /** */
 export class SidebarIndexItem extends Component {
   /** */
   render() {
     const {
-      classes, label,
+      label,
     } = this.props;
 
     return (
       <Typography
-        className={classNames(classes.label)}
         variant="body1"
       >
         {label}
@@ -23,6 +21,5 @@ export class SidebarIndexItem extends Component {
 }
 
 SidebarIndexItem.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   label: PropTypes.string.isRequired,
 };
diff --git a/src/components/SidebarIndexList.js b/src/components/SidebarIndexList.js
index 5cb8f6d860df95a419309e2ac5b91e704a71adc3..d19394ef97ec83f0718e161c4171f37446829a0d 100644
--- a/src/components/SidebarIndexList.js
+++ b/src/components/SidebarIndexList.js
@@ -1,12 +1,21 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import MenuList from '@material-ui/core/MenuList';
-import MenuItem from '@material-ui/core/MenuItem';
+import MenuList from '@mui/material/MenuList';
+import MenuItem from '@mui/material/MenuItem';
+import { styled } from '@mui/material/styles';
 import { ScrollTo } from './ScrollTo';
 import MiradorCanvas from '../lib/MiradorCanvas';
 import SidebarIndexItem from '../containers/SidebarIndexItem';
 import SidebarIndexThumbnail from '../containers/SidebarIndexThumbnail';
 
+const StyledItem = styled(MenuItem, { name: 'SidebarIndexList', slot: 'item' })(({ theme }) => ({
+  alignItems: 'flex-start',
+  paddingLeft: theme.spacing(2),
+  paddingRight: theme.spacing(1),
+  position: 'initial',
+  whiteSpace: 'normal',
+}));
+
 /** */
 export class SidebarIndexList extends Component {
   /** @private */
@@ -23,7 +32,6 @@ export class SidebarIndexList extends Component {
   render() {
     const {
       canvases,
-      classes,
       containerRef,
       selectedCanvasIds,
       setCanvas,
@@ -49,24 +57,22 @@ export class SidebarIndexList extends Component {
             const onClick = () => { setCanvas(windowId, canvas.id); }; // eslint-disable-line require-jsdoc, max-len
 
             return (
-              <MenuItem
-                key={canvas.id}
-                className={classes.listItem}
-                alignItems="flex-start"
-                onClick={onClick}
-                button
-                component="li"
+              <ScrollTo
+                containerRef={containerRef}
+                key={`${canvas.id}-${variant}`}
+                offsetTop={96} // offset for the height of the form above
                 selected={selectedCanvasIds.includes(canvas.id)}
+                scrollTo={selectedCanvasIds.includes(canvas.id)}
               >
-                <ScrollTo
-                  containerRef={containerRef}
-                  key={`${canvas.id}-${variant}`}
-                  offsetTop={96} // offset for the height of the form above
-                  scrollTo={selectedCanvasIds.includes(canvas.id)}
+                <StyledItem
+                  key={canvas.id}
+                  divider
+                  onClick={onClick}
+                  component="li"
                 >
                   <Item label={canvas.label} canvas={canvases[canvasIndex]} />
-                </ScrollTo>
-              </MenuItem>
+                </StyledItem>
+              </ScrollTo>
             );
           })
         }
@@ -77,7 +83,6 @@ export class SidebarIndexList extends Component {
 
 SidebarIndexList.propTypes = {
   canvases: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   containerRef: PropTypes.oneOf([PropTypes.func, PropTypes.object]).isRequired,
   selectedCanvasIds: PropTypes.arrayOf(PropTypes.string),
   setCanvas: PropTypes.func.isRequired,
diff --git a/src/components/SidebarIndexTableOfContents.js b/src/components/SidebarIndexTableOfContents.js
index e897a4e411a38738639f0ed6559945182229ee1f..296555e8c4ef73db40f56f37dea7211c62fa5492 100644
--- a/src/components/SidebarIndexTableOfContents.js
+++ b/src/components/SidebarIndexTableOfContents.js
@@ -1,12 +1,15 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import TreeView from '@material-ui/lab/TreeView';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
-import ChevronRightIcon from '@material-ui/icons/ChevronRight';
-import TreeItem from '@material-ui/lab/TreeItem';
-import clsx from 'clsx';
+import { alpha, styled } from '@mui/material/styles';
+import { TreeView } from '@mui/x-tree-view/TreeView';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import ChevronRightIcon from '@mui/icons-material/ChevronRight';
+import { TreeItem } from '@mui/x-tree-view/TreeItem';
 import { ScrollTo } from './ScrollTo';
 
+const StyledVisibleNode = styled('div')(() => ({
+
+}));
 /** */
 function getStartCanvasId(node) {
   const jsonld = node.data.__jsonld; // eslint-disable-line no-underscore-dangle
@@ -65,20 +68,13 @@ export class SidebarIndexTableOfContents extends Component {
   }
 
   /** */
-  handleKeyPressed(event, nodeId) {
+  handleNodeSelect(event, nodeId) {
     const { toggleNode } = this.props;
 
-    if (event.key === 'Enter') {
-      this.selectTreeItem(nodeId);
-    }
-
     if (event.key === ' ' || event.key === 'Spacebar') {
       toggleNode(nodeId);
     }
-  }
 
-  /** */
-  handleNodeSelect(_event, nodeId) {
     this.selectTreeItem(nodeId);
   }
 
@@ -109,7 +105,7 @@ export class SidebarIndexTableOfContents extends Component {
   /** */
   render() {
     const {
-      classes, treeStructure, visibleNodeIds, expandedNodeIds, containerRef, nodeIdToScrollTo,
+      treeStructure, visibleNodeIds, expandedNodeIds, containerRef, nodeIdToScrollTo,
     } = this.props;
 
     if (!treeStructure) {
@@ -127,22 +123,45 @@ export class SidebarIndexTableOfContents extends Component {
       >
         <TreeItem
           nodeId={node.id}
-          classes={{
-            content: classes.content,
-            group: classes.group,
-            label: classes.label,
-            root: classes.treeItemRoot,
-            selected: classes.selected,
+          sx={{
+            '& .MuiTreeItem-content': {
+              alignItems: 'flex-start',
+              borderLeft: '1px solid transparent',
+              padding: '8px 16px 8px 0',
+              width: 'auto',
+            },
+            '& .MuiTreeItem-group': {
+              borderLeft: '1px solid',
+              borderLeftColor: 'grey.300',
+            },
+            '& .MuiTreeItem-iconContainer': {
+              paddingBlockStart: 0.5,
+            },
+            '& .MuiTreeItem-label': {
+              paddingLeft: 0,
+            },
+            '& .MuiTreeItem-root': {
+              '&:focus > .MuiTreeItem-content': {
+                backgroundColor: 'action.selected',
+              },
+              '&:hover > .MuiTreeItem-content': {
+                backgroundColor: 'action.hover',
+              },
+              '&:hover > .MuiTreeItem-content .MuiTreeItem-label, &:focus > .MuiTreeItem-content .MuiTreeItem-label, &.MuiTreeItem-selected > .MuiTreeItem-content .MuiTreeItem-label, &.MuiTreeItem-selected > .MuiTreeItem-content .MuiTreeItem-label:hover, &.MuiTreeItem-selected:focus > .MuiTreeItem-content .MuiTreeItem-label': {
+                backgroundColor: 'transparent',
+              },
+            },
           }}
-          onKeyDown={e => this.handleKeyPressed(e, node.id)}
           label={(
-            <div
-              className={clsx({
-                [classes.visibleNode]: visibleNodeIds.indexOf(node.id) !== -1,
+            <StyledVisibleNode
+              sx={theme => ({
+                backgroundColor: visibleNodeIds.indexOf(node.id) !== -1
+                && alpha(theme.palette.highlights?.primary || theme.palette.action.selected, 0.35),
+                display: visibleNodeIds.indexOf(node.id) !== -1 && 'inline',
               })}
             >
               {node.label}
-            </div>
+            </StyledVisibleNode>
         )}
         >
           {Array.isArray(node.nodes) ? node.nodes.map((n) => renderTree(n)) : null}
@@ -152,7 +171,7 @@ export class SidebarIndexTableOfContents extends Component {
 
     return (
       <TreeView
-        className={classes.root}
+        sx={{ flexGrow: 1 }}
         defaultCollapseIcon={<ExpandMoreIcon color="action" />}
         defaultExpandIcon={<ChevronRightIcon color="action" />}
         defaultEndIcon={null}
@@ -167,7 +186,6 @@ export class SidebarIndexTableOfContents extends Component {
 }
 
 SidebarIndexTableOfContents.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   containerRef: PropTypes.oneOfType([
     PropTypes.func,
     PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
diff --git a/src/components/SidebarIndexThumbnail.js b/src/components/SidebarIndexThumbnail.js
index 7abd1973d6051d0e71e4c18bbaf40bd3a4031669..05126d8de02dc6d6d184bea3d94bb838607e9335 100644
--- a/src/components/SidebarIndexThumbnail.js
+++ b/src/components/SidebarIndexThumbnail.js
@@ -1,7 +1,6 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
-import classNames from 'classnames';
+import Typography from '@mui/material/Typography';
 import IIIFThumbnail from '../containers/IIIFThumbnail';
 
 /** */
@@ -9,7 +8,7 @@ export class SidebarIndexThumbnail extends Component {
   /** */
   render() {
     const {
-      classes, canvas, height, label, width,
+      canvas, height, label, width,
     } = this.props;
 
     return (
@@ -18,15 +17,11 @@ export class SidebarIndexThumbnail extends Component {
           <IIIFThumbnail
             label={label}
             resource={canvas}
-            className={classNames(classes.clickable)}
             maxHeight={height}
             maxWidth={width}
           />
         </div>
-        <Typography
-          className={classNames(classes.label)}
-          variant="body1"
-        >
+        <Typography>
           {label}
         </Typography>
       </>
@@ -36,7 +31,6 @@ export class SidebarIndexThumbnail extends Component {
 
 SidebarIndexThumbnail.propTypes = {
   canvas: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   height: PropTypes.number,
   label: PropTypes.string.isRequired,
   width: PropTypes.number,
diff --git a/src/components/ThumbnailCanvasGrouping.js b/src/components/ThumbnailCanvasGrouping.js
index 6e8902339c361816aad67a35f270418eee0eed4b..f01d399260c4e032e300683e73c133cec53cc130 100644
--- a/src/components/ThumbnailCanvasGrouping.js
+++ b/src/components/ThumbnailCanvasGrouping.js
@@ -1,9 +1,17 @@
 import { PureComponent } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import classNames from 'classnames';
 import IIIFThumbnail from '../containers/IIIFThumbnail';
 import ns from '../config/css-ns';
 
+const StyledCanvas = styled('div')(({ theme }) => ({
+  boxSizing: 'border-box',
+  color: theme.palette.common.white,
+  cursor: 'pointer',
+  display: 'inline-block',
+  whiteSpace: 'nowrap',
+}));
 /** */
 export class ThumbnailCanvasGrouping extends PureComponent {
   /** */
@@ -31,7 +39,7 @@ export class ThumbnailCanvasGrouping extends PureComponent {
   /** */
   render() {
     const {
-      index, style, data, classes, currentCanvasId,
+      index, style, data, currentCanvasId,
     } = this.props;
     const {
       canvasGroupings, position, height,
@@ -52,24 +60,27 @@ export class ThumbnailCanvasGrouping extends PureComponent {
         role="gridcell"
         aria-colindex={index + 1}
       >
-        <div
+        <StyledCanvas
           role="button"
           data-canvas-id={currentGroupings[0].id}
           data-canvas-index={currentGroupings[0].index}
           onKeyUp={this.setCanvas}
           onClick={this.setCanvas}
           tabIndex={-1}
-          style={{
+          sx={theme => ({
+            '&:hover': {
+              outline: `9px solid ${theme.palette.action.hover}`,
+              outlineOffset: '-2px',
+            },
             height: (position === 'far-right') ? 'auto' : `${height - SPACING}px`,
+            outline: currentGroupings.map(canvas => canvas.id).includes(currentCanvasId) ? `2px solid ${theme.palette.primary.main}` : 0,
+            ...(currentGroupings.map(canvas => canvas.id).includes(currentCanvasId) && {
+              outlineOffset: '3px',
+            }),
             width: (position === 'far-bottom') ? 'auto' : `${style.width}px`,
-          }}
+          })}
           className={classNames(
             ns(['thumbnail-nav-canvas', `thumbnail-nav-canvas-${index}`, this.currentCanvasClass(currentGroupings.map(canvas => canvas.index))]),
-            classes.canvas,
-            {
-              [classes.currentCanvas]: currentGroupings
-                .map(canvas => canvas.id).includes(currentCanvasId),
-            },
           )}
         >
           {currentGroupings.map((canvas, i) => (
@@ -81,14 +92,13 @@ export class ThumbnailCanvasGrouping extends PureComponent {
               variant="inside"
             />
           ))}
-        </div>
+        </StyledCanvas>
       </div>
     );
   }
 }
 
 ThumbnailCanvasGrouping.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   currentCanvasId: PropTypes.string.isRequired,
   data: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
   index: PropTypes.number.isRequired,
diff --git a/src/components/ThumbnailNavigation.js b/src/components/ThumbnailNavigation.js
index 59219d4446528d1b66c3cd300f5e137e1b1c20b3..1a4ce20cf69e8e7c9daf22151cc1c8aa4cadab01 100644
--- a/src/components/ThumbnailNavigation.js
+++ b/src/components/ThumbnailNavigation.js
@@ -1,6 +1,6 @@
 import { createRef, Component } from 'react';
 import PropTypes from 'prop-types';
-import Paper from '@material-ui/core/Paper';
+import Paper from '@mui/material/Paper';
 import AutoSizer from 'react-virtualized-auto-sizer';
 import { VariableSizeList as List } from 'react-window';
 import classNames from 'classnames';
@@ -176,7 +176,6 @@ export class ThumbnailNavigation extends Component {
     const {
       t,
       canvasGroupings,
-      classes,
       position,
       thumbnailNavigation,
       viewingDirection,
@@ -196,8 +195,13 @@ export class ThumbnailNavigation extends Component {
       <Paper
         className={classNames(
           ns('thumb-navigation'),
-          classes.thumbNavigation,
         )}
+        sx={{
+          '&:focus': {
+            boxShadow: 0,
+            outline: 0,
+          },
+        }}
         aria-label={t('thumbnailNavigation')}
         square
         elevation={0}
@@ -235,7 +239,6 @@ export class ThumbnailNavigation extends Component {
 ThumbnailNavigation.propTypes = {
   canvasGroupings: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
   canvasIndex: PropTypes.number.isRequired,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   hasNextCanvas: PropTypes.bool,
   hasPreviousCanvas: PropTypes.bool,
   position: PropTypes.string.isRequired,
diff --git a/src/components/VideoViewer.js b/src/components/VideoViewer.js
index e8a3d617df6b3f516fbacb7abcfd7b05c2894a78..a133aceed3b06116bd430d162afcbd70d6d8fa3d 100644
--- a/src/components/VideoViewer.js
+++ b/src/components/VideoViewer.js
@@ -1,5 +1,17 @@
 import { Component, Fragment } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
+
+const StyledContainer = styled('div')(() => ({
+  alignItems: 'center',
+  display: 'flex',
+  width: '100%',
+}));
+
+const StyledVideo = styled('video')(() => ({
+  maxHeight: '100%',
+  width: '100%',
+}));
 
 /** */
 export class VideoViewer extends Component {
@@ -7,11 +19,11 @@ export class VideoViewer extends Component {
   /** */
   render() {
     const {
-      captions, classes, videoOptions, videoResources,
+      captions, videoOptions, videoResources,
     } = this.props;
     return (
-      <div className={classes.container}>
-        <video className={classes.video} {...videoOptions}>
+      <StyledContainer>
+        <StyledVideo {...videoOptions}>
           {videoResources.map(video => (
             <Fragment key={video.id}>
               <source src={video.id} type={video.getFormat()} />
@@ -22,8 +34,8 @@ export class VideoViewer extends Component {
               <track src={caption.id} label={caption.getDefaultLabel()} srcLang={caption.getProperty('language')} />
             </Fragment>
           ))}
-        </video>
-      </div>
+        </StyledVideo>
+      </StyledContainer>
     );
   }
   /* eslint-enable jsx-a11y/media-has-caption */
@@ -31,7 +43,6 @@ export class VideoViewer extends Component {
 
 VideoViewer.propTypes = {
   captions: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   videoOptions: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   videoResources: PropTypes.arrayOf(PropTypes.object), // eslint-disable-line react/forbid-prop-types
 };
diff --git a/src/components/ViewerInfo.js b/src/components/ViewerInfo.js
index 595ed37d0f7c94bbef408772c3e39c419a14a481..1958bea5e714189630e6ecc586dcaa0f7b5b646b 100644
--- a/src/components/ViewerInfo.js
+++ b/src/components/ViewerInfo.js
@@ -1,9 +1,19 @@
 import { Component } from 'react';
-import Typography from '@material-ui/core/Typography';
+import Typography from '@mui/material/Typography';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import classNames from 'classnames';
 import ns from '../config/css-ns';
 
+const StyledOsdInfo = styled('div')(() => ({
+  overflow: 'hidden',
+  paddingBottom: 0.5,
+  textOverflow: 'ellipsis',
+  unicodeBidi: 'plaintext',
+  whiteSpace: 'nowrap',
+  width: '100%',
+}));
+
 /**
  *
  */
@@ -14,19 +24,18 @@ export class ViewerInfo extends Component {
       canvasCount,
       canvasIndex,
       canvasLabel,
-      classes,
       t,
     } = this.props;
 
     return (
-      <div className={classNames(ns('osd-info'), classes.osdInfo)}>
+      <StyledOsdInfo className={classNames(ns('osd-info'))}>
         <Typography display="inline" variant="caption" className={ns('canvas-count')}>
           { t('pagination', { current: canvasIndex + 1, total: canvasCount }) }
         </Typography>
         <Typography display="inline" variant="caption" className={ns('canvas-label')}>
           {canvasLabel && ` • ${canvasLabel}`}
         </Typography>
-      </div>
+      </StyledOsdInfo>
     );
   }
 }
@@ -40,6 +49,5 @@ ViewerInfo.propTypes = {
   canvasCount: PropTypes.number.isRequired,
   canvasIndex: PropTypes.number.isRequired,
   canvasLabel: PropTypes.string,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   t: PropTypes.func,
 };
diff --git a/src/components/ViewerNavigation.js b/src/components/ViewerNavigation.js
index 0253cefa5278df9db46b91480be5dac6c12362e2..e22b4ce4fac1b116b72654e80acd030042850e2e 100644
--- a/src/components/ViewerNavigation.js
+++ b/src/components/ViewerNavigation.js
@@ -1,5 +1,5 @@
 import { Component } from 'react';
-import NavigationIcon from '@material-ui/icons/PlayCircleOutlineSharp';
+import NavigationIcon from '@mui/icons-material/PlayCircleOutlineSharp';
 import PropTypes from 'prop-types';
 import classNames from 'classnames';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
@@ -14,7 +14,7 @@ export class ViewerNavigation extends Component {
   render() {
     const {
       hasNextCanvas, hasPreviousCanvas, setNextCanvas, setPreviousCanvas, t,
-      classes, viewingDirection,
+      viewingDirection,
     } = this.props;
 
     let htmlDir = 'ltr';
@@ -41,7 +41,7 @@ export class ViewerNavigation extends Component {
 
     return (
       <div
-        className={classNames(ns('osd-navigation'), classes.osdNavigation)}
+        className={classNames(ns('osd-navigation'))}
         dir={htmlDir}
       >
         <MiradorMenuButton
@@ -66,7 +66,6 @@ export class ViewerNavigation extends Component {
 }
 
 ViewerNavigation.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   hasNextCanvas: PropTypes.bool,
   hasPreviousCanvas: PropTypes.bool,
   setNextCanvas: PropTypes.func,
diff --git a/src/components/Window.js b/src/components/Window.js
index 6033c76919ba2e2364984d351fa2267eb4d93447..4610fb6cf2d4116f9edd1901bf6988a88b9c5b05 100644
--- a/src/components/Window.js
+++ b/src/components/Window.js
@@ -1,7 +1,7 @@
-import { Component } from 'react';
+import { Component, useContext } from 'react';
 import PropTypes from 'prop-types';
-import cn from 'classnames';
-import Paper from '@material-ui/core/Paper';
+import { styled } from '@mui/material/styles';
+import Paper from '@mui/material/Paper';
 import { MosaicWindowContext } from 'react-mosaic-component/lib/contextTypes';
 import ns from '../config/css-ns';
 import WindowTopBar from '../containers/WindowTopBar';
@@ -12,6 +12,68 @@ import ErrorContent from '../containers/ErrorContent';
 import IIIFAuthentication from '../containers/IIIFAuthentication';
 import { PluginHook } from './PluginHook';
 
+const rowMixin = {
+  display: 'flex',
+  flex: '1',
+  flexDirection: 'row',
+  minHeight: 0,
+};
+
+const columnMixin = {
+  display: 'flex',
+  flex: '1',
+  flexDirection: 'column',
+  minHeight: 0,
+};
+
+const Root = styled(Paper, { name: 'Window', slot: 'root' })(({ ownerState, theme }) => ({
+  ...columnMixin,
+  backgroundColor: theme.palette.shades?.dark,
+  borderRadius: 0,
+  height: '100%',
+  overflow: 'hidden',
+  width: '100%',
+  ...(ownerState?.maximized && {
+    left: 0,
+    position: 'absolute',
+    top: 0,
+    zIndex: theme.zIndex.modal - 1,
+  }),
+}));
+
+const ContentRow = styled('div', { name: 'Window', slot: 'row' })(() => ({
+  ...rowMixin,
+}));
+
+const ContentColumn = styled('div', { name: 'Window', slot: 'column' })(() => ({
+  ...columnMixin,
+}));
+
+const StyledPrimaryWindow = styled(PrimaryWindow, { name: 'Window', slot: 'primary' })(() => ({
+  ...rowMixin,
+  height: '300px',
+  position: 'relative',
+}));
+
+const StyledCompanionAreaBottom = styled(CompanionArea, { name: 'Window', slot: 'bottom' })(() => ({
+  ...rowMixin,
+  flex: '0',
+  flexBasis: 'auto',
+}));
+
+const StyledCompanionAreaRight = styled('div', { name: 'Window', slot: 'right' })(() => ({
+  ...rowMixin,
+  flex: '0 1 auto',
+}));
+
+/** Window title bar wrapper for drag controls in the mosaic view */
+const DraggableNavBar = ({ children, ...props }) => {
+  const { mosaicWindowActions } = useContext(MosaicWindowContext);
+  return mosaicWindowActions.connectDragSource(
+    <nav {...props}>{children}</nav>,
+  );
+};
+
 /**
  * Represents a Window in the mirador workspace
  * @param {object} window
@@ -29,40 +91,13 @@ export class Window extends Component {
     return { error, hasError: true };
   }
 
-  /**
-   * wrappedTopBar - will conditionally wrap a WindowTopBar for needed
-   * additional functionality based on workspace type
-   */
-  wrappedTopBar() {
-    const {
-      windowId, workspaceType, windowDraggable,
-    } = this.props;
-
-    const topBar = (
-      <div>
-        <WindowTopBar
-          windowId={windowId}
-          windowDraggable={windowDraggable}
-        />
-        <IIIFAuthentication windowId={windowId} />
-      </div>
-    );
-    if (workspaceType === 'mosaic' && windowDraggable) {
-      const { mosaicWindowActions } = this.context;
-      return mosaicWindowActions.connectDragSource(
-        topBar,
-      );
-    }
-    return topBar;
-  }
-
   /**
    * Renders things
    */
   render() {
     const {
-      focusWindow, label, isFetching, maximized, sideBarOpen,
-      view, windowId, classes, t,
+      focusWindow, label, isFetching, sideBarOpen,
+      view, windowDraggable, windowId, workspaceType, t,
       manifestError,
     } = this.props;
 
@@ -77,44 +112,40 @@ export class Window extends Component {
     }
 
     return (
-      <Paper
+      <Root
         onFocus={focusWindow}
+        ownerState={this.props}
         component="section"
         elevation={1}
         id={windowId}
-        className={
-          cn(
-            classes.window,
-            ns('window'),
-            maximized ? classes.maximized : null,
-          )
-}
+        className={ns('window')}
         aria-label={t('window', { label })}
       >
-        {this.wrappedTopBar()}
+        <WindowTopBar
+          component={workspaceType === 'mosaic' && windowDraggable ? DraggableNavBar : undefined}
+          windowId={windowId}
+          windowDraggable={windowDraggable}
+        />
+        <IIIFAuthentication windowId={windowId} />
         { manifestError && <ErrorContent error={{ stack: manifestError }} windowId={windowId} /> }
-        <div className={classes.middle}>
-          <div className={classes.middleLeft}>
-            <div className={classes.primaryWindow}>
-              <PrimaryWindow
-                view={view}
-                windowId={windowId}
-                isFetching={isFetching}
-                sideBarOpen={sideBarOpen}
-              />
-            </div>
-            <div className={classes.companionAreaBottom}>
-              <CompanionArea windowId={windowId} position="bottom" />
-            </div>
-          </div>
-          <div className={classes.companionAreaRight}>
+        <ContentRow>
+          <ContentColumn>
+            <StyledPrimaryWindow
+              view={view}
+              windowId={windowId}
+              isFetching={isFetching}
+              sideBarOpen={sideBarOpen}
+            />
+            <StyledCompanionAreaBottom windowId={windowId} position="bottom" />
+          </ContentColumn>
+          <StyledCompanionAreaRight>
             <CompanionArea windowId={windowId} position="right" />
             <CompanionArea windowId={windowId} position="far-right" />
-          </div>
-        </div>
+          </StyledCompanionAreaRight>
+        </ContentRow>
         <CompanionArea windowId={windowId} position="far-bottom" />
         <PluginHook {...this.props} />
-      </Paper>
+      </Root>
     );
   }
 }
@@ -122,7 +153,6 @@ export class Window extends Component {
 Window.contextType = MosaicWindowContext;
 
 Window.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string),
   focusWindow: PropTypes.func,
   isFetching: PropTypes.bool,
   label: PropTypes.string,
@@ -137,7 +167,6 @@ Window.propTypes = {
 };
 
 Window.defaultProps = {
-  classes: {},
   focusWindow: () => {},
   isFetching: false,
   label: null,
diff --git a/src/components/WindowAuthenticationBar.js b/src/components/WindowAuthenticationBar.js
index bbfbd5a5388cc7889297364298b394c23edcdb96..05d2a365f69dd75d1c3bd331d9c8d8a9079e376f 100644
--- a/src/components/WindowAuthenticationBar.js
+++ b/src/components/WindowAuthenticationBar.js
@@ -1,14 +1,26 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Button from '@material-ui/core/Button';
-import Paper from '@material-ui/core/Paper';
-import Collapse from '@material-ui/core/Collapse';
-import DialogActions from '@material-ui/core/DialogActions';
-import Typography from '@material-ui/core/Typography';
-import LockIcon from '@material-ui/icons/LockSharp';
+import { alpha, styled } from '@mui/material/styles';
+import Button from '@mui/material/Button';
+import Paper from '@mui/material/Paper';
+import Collapse from '@mui/material/Collapse';
+import DialogActions from '@mui/material/DialogActions';
+import Typography from '@mui/material/Typography';
+import LockIcon from '@mui/icons-material/LockSharp';
 import SanitizedHtml from '../containers/SanitizedHtml';
 import { PluginHook } from './PluginHook';
 
+const StyledTopBar = styled('div')(({ theme }) => ({
+  '&:hover': {
+    backgroundColor: theme.palette.secondary.main,
+  },
+  alignItems: 'center',
+  display: 'flex',
+}));
+
+const StyledFauxButton = styled('span')(({ theme }) => ({
+  marginLeft: theme.spacing(2.5),
+}));
 /** */
 export class WindowAuthenticationBar extends Component {
   /** */
@@ -35,7 +47,7 @@ export class WindowAuthenticationBar extends Component {
   /** */
   render() {
     const {
-      classes, confirmButton, continueLabel,
+      confirmButton, continueLabel,
       header, description, icon, label, t,
       ruleSet, hasLogoutService, status, ConfirmProps,
     } = this.props;
@@ -45,47 +57,90 @@ export class WindowAuthenticationBar extends Component {
     const { open } = this.state;
 
     const button = (
-      <Button onClick={this.onSubmit} className={classes.buttonInvert} color="secondary" {...ConfirmProps}>
+      <Button
+        onClick={this.onSubmit}
+        color="secondary"
+        sx={(theme) => ({
+          '&:hover': {
+            backgroundColor: alpha(theme.palette.secondary.contrastText, 1 - theme.palette.action.hoverOpacity),
+          },
+          backgroundColor: theme.palette.secondary.contrastText,
+        })}
+        {...ConfirmProps}
+      >
         {confirmButton || t('login')}
       </Button>
     );
 
     if (!description && !header) {
       return (
-        <Paper square elevation={4} color="secondary" classes={{ root: classes.paper }}>
-          <div className={classes.topBar}>
-            { icon || <LockIcon className={classes.icon} /> }
-            <Typography className={classes.label} component="h3" variant="body1" color="inherit">
+        <Paper
+          square
+          elevation={4}
+          color="secondary"
+        >
+          <StyledTopBar>
+            { icon || (
+              <LockIcon sx={{ marginInlineEnd: 1.5 }} />
+            ) }
+            <Typography component="h3" variant="body1" color="inherit">
               { ruleSet ? <SanitizedHtml htmlString={label} ruleSet={ruleSet} /> : label }
             </Typography>
             <PluginHook {...this.props} />
             { button }
-          </div>
+          </StyledTopBar>
         </Paper>
       );
     }
 
     return (
-      <Paper square elevation={4} color="secondary" classes={{ root: classes.paper }}>
-        <Button fullWidth className={classes.topBar} onClick={() => this.setOpen(true)} component="div" color="inherit">
-          { icon || <LockIcon className={classes.icon} /> }
-          <Typography className={classes.label} component="h3" variant="body1" color="inherit">
+      <Paper
+        square
+        elevation={4}
+        color="secondary"
+      >
+        <Button
+          fullWidth
+          onClick={() => this.setOpen(true)}
+          component="div"
+          color="inherit"
+          sx={(theme) => ({
+            '&:hover': {
+              backgroundColor: theme.palette.secondary.main,
+            },
+            backgroundColor: theme.palette.secondary.main,
+            borderRadius: 0,
+            color: theme.palette.secondary.contrastText,
+            justifyContent: 'start',
+            textTransform: 'none',
+          })}
+        >
+          { icon || (
+          <LockIcon sx={{ marginInlineEnd: 1.5 }} />
+          ) }
+          <Typography sx={{ paddingBlockEnd: 1, paddingBlockStart: 1 }} component="h3" variant="body1" color="inherit">
             { ruleSet ? <SanitizedHtml htmlString={label} ruleSet={ruleSet} /> : label }
           </Typography>
           <PluginHook {...this.props} />
-          <span className={classes.fauxButton}>
+          <StyledFauxButton>
             { !open && (
               <Typography variant="button" color="inherit">
                 { continueLabel || t('continue') }
               </Typography>
             )}
-          </span>
+          </StyledFauxButton>
         </Button>
         <Collapse
+          sx={(theme) => ({
+            backgroundColor: theme.palette.secondary.main,
+            color: theme.palette.secondary.contrastText,
+            paddingInlineEnd: theme.spacing(1),
+            paddingInlineStart: theme.spacing(1),
+          })}
           in={open}
           onClose={() => this.setOpen(false)}
         >
-          <Typography variant="body1" color="inherit" className={classes.expanded}>
+          <Typography variant="body1" color="inherit">
             { ruleSet ? <SanitizedHtml htmlString={header} ruleSet={ruleSet} /> : header }
             { header && description ? ': ' : '' }
             { ruleSet ? <SanitizedHtml htmlString={description} ruleSet={ruleSet} /> : description }
@@ -104,7 +159,6 @@ export class WindowAuthenticationBar extends Component {
 }
 
 WindowAuthenticationBar.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   confirmButton: PropTypes.string,
   ConfirmProps: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   continueLabel: PropTypes.string,
diff --git a/src/components/WindowCanvasNavigationControls.js b/src/components/WindowCanvasNavigationControls.js
index eaee4dc152d82477faf268ccb1f636010fda3647..df9e3ae73788c18d6993a394211704d329d8edda 100644
--- a/src/components/WindowCanvasNavigationControls.js
+++ b/src/components/WindowCanvasNavigationControls.js
@@ -1,14 +1,33 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
+import { alpha, styled } from '@mui/material/styles';
 import classNames from 'classnames';
-import Paper from '@material-ui/core/Paper';
-import Typography from '@material-ui/core/Typography';
+import Paper from '@mui/material/Paper';
+import Stack from '@mui/material/Stack';
+import Divider from '@mui/material/Divider';
+import Typography from '@mui/material/Typography';
+import { visuallyHidden } from '@mui/utils';
 import ZoomControls from '../containers/ZoomControls';
 import ViewerInfo from '../containers/ViewerInfo';
 import ViewerNavigation from '../containers/ViewerNavigation';
 import ns from '../config/css-ns';
 import { PluginHook } from './PluginHook';
 
+const Root = styled(Paper, { name: 'WindowCanvasNavigationControls', slot: 'root' })(({ theme }) => ({
+  alignItems: 'center',
+  backgroundColor: alpha(theme.palette.background.paper, 0.5),
+  bottom: 0,
+  cursor: 'default',
+  display: 'flex',
+  flexDirection: 'column',
+  flexWrap: 'wrap',
+  justifyContent: 'center',
+  position: 'absolute',
+  textAlign: 'center',
+  width: '100%',
+  zIndex: 50,
+}));
+
 /**
  * Represents the viewer controls in the mirador workspace.
  */
@@ -25,41 +44,40 @@ export class WindowCanvasNavigationControls extends Component {
   /** */
   render() {
     const {
-      classes, visible, windowId, zoomToWorld,
+      showZoomControls, visible, windowId, zoomToWorld,
     } = this.props;
 
-    if (!visible) return (<Typography variant="srOnly" component="div"><ViewerInfo windowId={windowId} /></Typography>);
+    if (!visible) return (<Typography style={visuallyHidden} component="div"><ViewerInfo windowId={windowId} /></Typography>);
 
     return (
-      <Paper
+      <Root
         square
         className={
           classNames(
-            classes.controls,
             ns('canvas-nav'),
-            classes.canvasNav,
             this.canvasNavControlsAreStacked() ? ns('canvas-nav-stacked') : null,
-            this.canvasNavControlsAreStacked() ? classes.canvasNavStacked : null,
           )
-}
+        }
         elevation={0}
       >
-        <ZoomControls
-          displayDivider={!this.canvasNavControlsAreStacked()}
-          windowId={windowId}
-          zoomToWorld={zoomToWorld}
-        />
-        <ViewerNavigation windowId={windowId} />
+        <Stack
+          direction={this.canvasNavControlsAreStacked() ? 'column' : 'row'}
+          divider={<Divider orientation={this.canvasNavControlsAreStacked() ? 'horizontal' : 'vertical'} variant="middle" flexItem />}
+          spacing={0}
+        >
+          { showZoomControls && <ZoomControls windowId={windowId} zoomToWorld={zoomToWorld} /> }
+          <ViewerNavigation windowId={windowId} />
+        </Stack>
         <ViewerInfo windowId={windowId} />
 
         <PluginHook {...this.props} />
-      </Paper>
+      </Root>
     );
   }
 }
 
 WindowCanvasNavigationControls.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string),
+  showZoomControls: PropTypes.bool,
   size: PropTypes.shape({ width: PropTypes.number }).isRequired,
   visible: PropTypes.bool,
   windowId: PropTypes.string.isRequired,
@@ -67,6 +85,6 @@ WindowCanvasNavigationControls.propTypes = {
 };
 
 WindowCanvasNavigationControls.defaultProps = {
-  classes: {},
+  showZoomControls: false,
   visible: true,
 };
diff --git a/src/components/WindowList.js b/src/components/WindowList.js
index 8ed83f402ca09c3a7c495b3ae1094229e9ff85ec..2db96ba42b70f6672147013dfadac62309f3ad2f 100644
--- a/src/components/WindowList.js
+++ b/src/components/WindowList.js
@@ -1,8 +1,8 @@
 import { Component } from 'react';
-import Menu from '@material-ui/core/Menu';
-import MenuItem from '@material-ui/core/MenuItem';
-import ListItemText from '@material-ui/core/ListItemText';
-import ListSubheader from '@material-ui/core/ListSubheader';
+import Menu from '@mui/material/Menu';
+import MenuItem from '@mui/material/MenuItem';
+import ListItemText from '@mui/material/ListItemText';
+import ListSubheader from '@mui/material/ListSubheader';
 import PropTypes from 'prop-types';
 
 /**
diff --git a/src/components/WindowListButton.js b/src/components/WindowListButton.js
index 68a9bd2ac974089ddfb88609ab29b27bb4cf5954..758e227ac71202a71e2da63f7474852d608de962 100644
--- a/src/components/WindowListButton.js
+++ b/src/components/WindowListButton.js
@@ -1,7 +1,6 @@
 import { Component } from 'react';
-import BookmarksIcon from '@material-ui/icons/BookmarksSharp';
+import BookmarksIcon from '@mui/icons-material/BookmarksSharp';
 import PropTypes from 'prop-types';
-import classNames from 'classnames';
 import WindowList from '../containers/WindowList';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 
@@ -33,7 +32,7 @@ export class WindowListButton extends Component {
   */
   render() {
     const {
-      classes, disabled, t, windowCount,
+      disabled, t, windowCount,
     } = this.props;
     const { windowListAnchor } = this.state;
 
@@ -43,24 +42,29 @@ export class WindowListButton extends Component {
           aria-haspopup="true"
           aria-label={t('listAllOpenWindows')}
           aria-owns={windowListAnchor ? 'window-list' : null}
-          className={
-            classNames(classes.ctrlBtn, (windowListAnchor ? classes.ctrlBtnSelected : null))
-          }
+          selected={Boolean(windowListAnchor)}
           disabled={disabled}
           badge
-          BadgeProps={{ badgeContent: windowCount, classes: { badge: classes.badge } }}
-          onClick={e => this.handleOpen(e)}
+          BadgeProps={{
+            badgeContent: windowCount,
+            sx: {
+              '.MuiBadge-badge': {
+                paddingLeft: 1.5,
+              },
+            },
+          }}
+          onClick={(e) => this.handleOpen(e)}
         >
           <BookmarksIcon />
         </MiradorMenuButton>
 
         {Boolean(windowListAnchor) && (
-          <WindowList
-            anchorEl={windowListAnchor}
-            id="window-list"
-            open={Boolean(windowListAnchor)}
-            handleClose={this.handleClose}
-          />
+        <WindowList
+          anchorEl={windowListAnchor}
+          id="window-list"
+          open={Boolean(windowListAnchor)}
+          handleClose={this.handleClose}
+        />
         )}
       </>
     );
@@ -68,12 +72,10 @@ export class WindowListButton extends Component {
 }
 
 WindowListButton.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string),
   disabled: PropTypes.bool,
   t: PropTypes.func.isRequired,
   windowCount: PropTypes.number.isRequired,
 };
 WindowListButton.defaultProps = {
-  classes: {},
   disabled: false,
 };
diff --git a/src/components/WindowSideBar.js b/src/components/WindowSideBar.js
index c6fbc6ef3f75ecd493fc2a36b9df35fe234539f6..7750eeb294d9e3e9e42651fbd7870da8a999e37b 100644
--- a/src/components/WindowSideBar.js
+++ b/src/components/WindowSideBar.js
@@ -1,9 +1,20 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import classNames from 'classnames';
-import Drawer from '@material-ui/core/Drawer';
+import { styled } from '@mui/material/styles';
+import Drawer from '@mui/material/Drawer';
 import WindowSideBarButtons from '../containers/WindowSideBarButtons';
 
+const Root = styled(Drawer, { name: 'WindowSideBar', slot: 'root' })(({ theme }) => ({
+  flexShrink: 0,
+  order: -1000,
+  zIndex: theme.zIndex.appBar - 1,
+}));
+
+const Nav = styled('nav', { name: 'WindowSideBar', slot: 'nav' })({
+  position: 'relative !important',
+  width: 48,
+});
+
 /**
  * WindowSideBar
  */
@@ -18,27 +29,26 @@ export class WindowSideBar extends Component {
     } = this.props;
 
     return (
-      <Drawer
+      <Root
         variant="persistent"
-        className={classNames(classes.drawer)}
-        classes={{ paper: classNames(classes.paper) }}
+        className={classes.drawer}
         anchor={direction === 'rtl' ? 'right' : 'left'}
         PaperProps={{
           'aria-label': t('sidebarPanelsNavigation'),
-          component: 'nav',
-          style: { height: '100%', position: 'relative' },
+          component: Nav,
+          variant: 'outlined',
         }}
         SlideProps={{ direction: direction === 'rtl' ? 'left' : 'right', mountOnEnter: true, unmountOnExit: true }}
         open={sideBarOpen}
       >
         <WindowSideBarButtons windowId={windowId} />
-      </Drawer>
+      </Root>
     );
   }
 }
 
 WindowSideBar.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
+  classes: PropTypes.objectOf(PropTypes.string),
   direction: PropTypes.string.isRequired,
   sideBarOpen: PropTypes.bool,
   t: PropTypes.func.isRequired,
@@ -46,5 +56,6 @@ WindowSideBar.propTypes = {
 };
 
 WindowSideBar.defaultProps = {
+  classes: {},
   sideBarOpen: false,
 };
diff --git a/src/components/WindowSideBarAnnotationsPanel.js b/src/components/WindowSideBarAnnotationsPanel.js
index f5182e6443dcfc8430aba05f808200e6ac83f25b..d2e6f781d0c3b160395df19809fa5f2ea39dc846 100644
--- a/src/components/WindowSideBarAnnotationsPanel.js
+++ b/src/components/WindowSideBarAnnotationsPanel.js
@@ -1,9 +1,10 @@
 import { createRef, Component } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
+import Typography from '@mui/material/Typography';
 import AnnotationSettings from '../containers/AnnotationSettings';
 import CanvasAnnotations from '../containers/CanvasAnnotations';
 import CompanionWindow from '../containers/CompanionWindow';
+import { CompanionWindowSection } from './CompanionWindowSection';
 import ns from '../config/css-ns';
 
 /**
@@ -22,7 +23,7 @@ export class WindowSideBarAnnotationsPanel extends Component {
   */
   render() {
     const {
-      annotationCount, classes, canvasIds, t, windowId, id,
+      annotationCount, canvasIds, t, windowId, id,
     } = this.props;
     return (
       <CompanionWindow
@@ -31,12 +32,11 @@ export class WindowSideBarAnnotationsPanel extends Component {
         windowId={windowId}
         id={id}
         ref={this.containerRef}
-        otherRef={this.containerRef}
         titleControls={<AnnotationSettings windowId={windowId} />}
       >
-        <div className={classes.section}>
+        <CompanionWindowSection>
           <Typography component="p" variant="subtitle2">{t('showingNumAnnotations', { count: annotationCount, number: annotationCount })}</Typography>
-        </div>
+        </CompanionWindowSection>
 
         {canvasIds.map((canvasId, index) => (
           <CanvasAnnotations
@@ -56,7 +56,6 @@ export class WindowSideBarAnnotationsPanel extends Component {
 WindowSideBarAnnotationsPanel.propTypes = {
   annotationCount: PropTypes.number.isRequired,
   canvasIds: PropTypes.arrayOf(PropTypes.string),
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   id: PropTypes.string.isRequired,
   t: PropTypes.func,
   windowId: PropTypes.string.isRequired,
diff --git a/src/components/WindowSideBarButtons.js b/src/components/WindowSideBarButtons.js
index e4b0a2f6cc7cd6d1128d40e392b7d3d59a49eff9..bba780d3d62a01e7da62d25287bc628aa4b7af42 100644
--- a/src/components/WindowSideBarButtons.js
+++ b/src/components/WindowSideBarButtons.js
@@ -1,21 +1,62 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Badge from '@material-ui/core/Badge';
-import Tabs from '@material-ui/core/Tabs';
-import Tab from '@material-ui/core/Tab';
-import Tooltip from '@material-ui/core/Tooltip';
-import InfoIcon from '@material-ui/icons/InfoSharp';
-import AnnotationIcon from '@material-ui/icons/CommentSharp';
-import AttributionIcon from '@material-ui/icons/CopyrightSharp';
-import LayersIcon from '@material-ui/icons/LayersSharp';
-import SearchIcon from '@material-ui/icons/SearchSharp';
+import { styled } from '@mui/material/styles';
+import Badge from '@mui/material/Badge';
+import Tabs from '@mui/material/Tabs';
+import Tab from '@mui/material/Tab';
+import Tooltip from '@mui/material/Tooltip';
+import InfoIcon from '@mui/icons-material/InfoSharp';
+import AnnotationIcon from '@mui/icons-material/CommentSharp';
+import AttributionIcon from '@mui/icons-material/CopyrightSharp';
+import LayersIcon from '@mui/icons-material/LayersSharp';
+import SearchIcon from '@mui/icons-material/SearchSharp';
 import CanvasIndexIcon from './icons/CanvasIndexIcon';
 
+const Root = styled(Tabs, { name: 'WindowSideBarButtons', slot: 'root' })({
+  '& .MuiTabs-flexContainer': {
+    flexDirection: 'column',
+  },
+  '&.MuiTabs-indicator': {
+    display: 'none',
+  },
+});
+
+const StyledTabButton = styled(Tab, { name: 'WindowSideBarButtons', slot: 'button' })(({ theme }) => ({
+  '&.Mui-selected': {
+    borderRight: '2px solid',
+    borderRightColor: theme.palette.primary.main,
+  },
+  '&.MuiTab-root': {
+    '&:active': {
+      backgroundColor: theme.palette.action.active,
+    },
+    '&:focus': {
+      '@media (hover: none)': {
+        backgroundColor: 'transparent',
+      },
+      backgroundColor: theme.palette.action.hover,
+      textDecoration: 'none',
+      // Reset on touch devices, it doesn't add specificity
+    },
+    '&:hover': {
+      '@media (hover: none)': {
+        backgroundColor: 'transparent',
+      },
+      backgroundColor: theme.palette.action.hover,
+      textDecoration: 'none',
+      // Reset on touch devices, it doesn't add specificity
+    },
+    borderRight: '2px solid transparent',
+    minWidth: 'auto',
+  },
+  fill: 'currentcolor',
+}));
+
 /** */
 function TabButton({ t, value, ...tabProps }) {
   return (
     <Tooltip title={t('openCompanionWindow', { context: value })}>
-      <Tab
+      <StyledTabButton
         {...tabProps}
         value={value}
         aria-label={
@@ -59,7 +100,6 @@ export class WindowSideBarButtons extends Component {
    */
   render() {
     const {
-      classes,
       hasAnnotations,
       hasAnyAnnotations,
       hasAnyLayers,
@@ -73,8 +113,7 @@ export class WindowSideBarButtons extends Component {
     } = this.props;
 
     return (
-      <Tabs
-        classes={{ flexContainer: classes.tabsFlexContainer, indicator: classes.tabsIndicator }}
+      <Root
         value={sideBarPanel === 'closed' ? false : sideBarPanel}
         onChange={this.handleChange}
         variant="fullWidth"
@@ -88,7 +127,6 @@ export class WindowSideBarButtons extends Component {
           <TabButton
             value="info"
             onKeyUp={this.handleKeyUp}
-            classes={{ root: classes.tab, selected: classes.tabSelected }}
             t={t}
             icon={(<InfoIcon />)}
           />
@@ -97,7 +135,6 @@ export class WindowSideBarButtons extends Component {
           <TabButton
             value="attribution"
             onKeyUp={this.handleKeyUp}
-            classes={{ root: classes.tab, selected: classes.tabSelected }}
             t={t}
             icon={(<AttributionIcon />)}
           />
@@ -106,7 +143,6 @@ export class WindowSideBarButtons extends Component {
           <TabButton
             value="canvas"
             onKeyUp={this.handleKeyUp}
-            classes={{ root: classes.tab, selected: classes.tabSelected }}
             t={t}
             icon={(<CanvasIndexIcon />)}
           />
@@ -115,10 +151,9 @@ export class WindowSideBarButtons extends Component {
           <TabButton
             value="annotations"
             onKeyUp={this.handleKeyUp}
-            classes={{ root: classes.tab, selected: classes.tabSelected }}
             t={t}
             icon={(
-              <Badge overlap="rectangular" classes={{ badge: classes.badge }} invisible={!hasAnnotations} variant="dot">
+              <Badge overlap="rectangular" color="notification" invisible={!hasAnnotations} variant="dot">
                 <AnnotationIcon />
               </Badge>
             )}
@@ -128,10 +163,9 @@ export class WindowSideBarButtons extends Component {
           <TabButton
             value="search"
             onKeyUp={this.handleKeyUp}
-            classes={{ root: classes.tab, selected: classes.tabSelected }}
             t={t}
             icon={(
-              <Badge overlap="rectangular" classes={{ badge: classes.badge }} invisible={!hasSearchResults} variant="dot">
+              <Badge overlap="rectangular" color="notification" invisible={!hasSearchResults} variant="dot">
                 <SearchIcon />
               </Badge>
             )}
@@ -141,10 +175,9 @@ export class WindowSideBarButtons extends Component {
           <TabButton
             value="layers"
             onKeyUp={this.handleKeyUp}
-            classes={{ root: classes.tab, selected: classes.tabSelected }}
             t={t}
             icon={(
-              <Badge overlap="rectangular" classes={{ badge: classes.badge }} invisible={!hasCurrentLayers} variant="dot">
+              <Badge overlap="rectangular" color="notification" invisible={!hasCurrentLayers} variant="dot">
                 <LayersIcon />
               </Badge>
             )}
@@ -154,21 +187,19 @@ export class WindowSideBarButtons extends Component {
           && PluginComponents.map(PluginComponent => (
             <TabButton
               onKeyUp={this.handleKeyUp}
-              classes={{ root: classes.tab, selected: classes.tabSelected }}
               t={t}
               key={PluginComponent.value}
               value={PluginComponent.value}
               icon={<PluginComponent />}
             />
           ))}
-      </Tabs>
+      </Root>
     );
   }
 }
 
 WindowSideBarButtons.propTypes = {
   addCompanionWindow: PropTypes.func.isRequired,
-  classes: PropTypes.objectOf(PropTypes.string),
   hasAnnotations: PropTypes.bool,
   hasAnyAnnotations: PropTypes.bool,
   hasAnyLayers: PropTypes.bool,
@@ -182,7 +213,6 @@ WindowSideBarButtons.propTypes = {
 };
 
 WindowSideBarButtons.defaultProps = {
-  classes: {},
   hasAnnotations: false,
   hasAnyAnnotations: false,
   hasAnyLayers: false,
diff --git a/src/components/WindowSideBarCanvasPanel.js b/src/components/WindowSideBarCanvasPanel.js
index d785b5abe23635693be6a1d8616fd8eaaf9d3779..768f8c65d5a4e5d062479d8ca9c57719e13bc5b2 100644
--- a/src/components/WindowSideBarCanvasPanel.js
+++ b/src/components/WindowSideBarCanvasPanel.js
@@ -1,21 +1,26 @@
 import { createRef, Component } from 'react';
 import PropTypes from 'prop-types';
-import Tabs from '@material-ui/core/Tabs';
-import Tab from '@material-ui/core/Tab';
-import Tooltip from '@material-ui/core/Tooltip';
-import Button from '@material-ui/core/Button';
-import ItemListIcon from '@material-ui/icons/ReorderSharp';
-import TocIcon from '@material-ui/icons/SortSharp';
-import ThumbnailListIcon from '@material-ui/icons/ViewListSharp';
-import Typography from '@material-ui/core/Typography';
-import ArrowForwardIcon from '@material-ui/icons/ArrowForwardSharp';
-import FormControl from '@material-ui/core/FormControl';
-import Select from '@material-ui/core/Select';
-import MenuItem from '@material-ui/core/MenuItem';
+import { styled } from '@mui/material/styles';
+import Tabs from '@mui/material/Tabs';
+import Tab from '@mui/material/Tab';
+import Tooltip from '@mui/material/Tooltip';
+import Button from '@mui/material/Button';
+import ItemListIcon from '@mui/icons-material/ReorderSharp';
+import TocIcon from '@mui/icons-material/SortSharp';
+import ThumbnailListIcon from '@mui/icons-material/ViewListSharp';
+import Typography from '@mui/material/Typography';
+import ArrowForwardIcon from '@mui/icons-material/ArrowForwardSharp';
+import FormControl from '@mui/material/FormControl';
+import Select from '@mui/material/Select';
+import MenuItem from '@mui/material/MenuItem';
 import CompanionWindow from '../containers/CompanionWindow';
 import SidebarIndexList from '../containers/SidebarIndexList';
 import SidebarIndexTableOfContents from '../containers/SidebarIndexTableOfContents';
 
+const StyledBreak = styled('div')(() => ({
+  flexBasis: '100%',
+  height: 0,
+}));
 /**
  * a panel showing the canvases for a given manifest
  */
@@ -57,7 +62,6 @@ export class WindowSideBarCanvasPanel extends Component {
    */
   render() {
     const {
-      classes,
       collection,
       id,
       showMultipart,
@@ -95,7 +99,6 @@ export class WindowSideBarCanvasPanel extends Component {
         id={id}
         windowId={windowId}
         ref={this.containerRef}
-        otherRef={this.containerRef}
         titleControls={(
           <>
             {
@@ -107,14 +110,19 @@ export class WindowSideBarCanvasPanel extends Component {
                         horizontal: 'left',
                         vertical: 'bottom',
                       },
-                      getContentAnchorEl: null,
                     }}
                     displayEmpty
                     value={sequenceId}
                     onChange={this.handleSequenceChange}
                     name="sequenceId"
-                    classes={{ select: classes.select }}
-                    className={classes.selectEmpty}
+                    sx={{
+                      '&.MuiSelect-select': {
+                        '&:focus': {
+                          backgroundColor: 'background.paper',
+                        },
+                      },
+                      backgroundColor: 'background.paper',
+                    }}
                     data-testid="sequence-select"
                   >
                     { sequences.map((s, i) => <MenuItem value={s.id} key={s.id}><Typography variant="body2">{ WindowSideBarCanvasPanel.getUseableLabel(s, i) }</Typography></MenuItem>) }
@@ -122,7 +130,7 @@ export class WindowSideBarCanvasPanel extends Component {
                 </FormControl>
               )
             }
-            <div className={classes.break} />
+            <StyledBreak />
             <Tabs
               value={variant}
               onChange={this.handleVariantChange}
@@ -131,10 +139,10 @@ export class WindowSideBarCanvasPanel extends Component {
               textColor="primary"
             >
               {showToc && (
-                <Tooltip title={t('tableOfContentsList')} value="tableOfContents"><Tab className={classes.variantTab} value="tableOfContents" aria-label={t('tableOfContentsList')} aria-controls={`tab-panel-${id}`} icon={<TocIcon style={{ transform: 'scale(-1, 1)' }} />} /></Tooltip>
+                <Tooltip title={t('tableOfContentsList')} value="tableOfContents"><Tab sx={{ minWidth: 'auto' }} value="tableOfContents" aria-label={t('tableOfContentsList')} aria-controls={`tab-panel-${id}`} icon={<TocIcon style={{ transform: 'scale(-1, 1)' }} />} /></Tooltip>
               )}
-              <Tooltip title={t('itemList')} value="item"><Tab className={classes.variantTab} value="item" aria-label={t('itemList')} aria-controls={`tab-panel-${id}`} icon={<ItemListIcon />} /></Tooltip>
-              <Tooltip title={t('thumbnailList')} value="thumbnail"><Tab className={classes.variantTab} value="thumbnail" aria-label={t('thumbnailList')} aria-controls={`tab-panel-${id}`} icon={<ThumbnailListIcon />} /></Tooltip>
+              <Tooltip title={t('itemList')} value="item"><Tab sx={{ minWidth: 'auto' }} value="item" aria-label={t('itemList')} aria-controls={`tab-panel-${id}`} icon={<ItemListIcon />} /></Tooltip>
+              <Tooltip title={t('thumbnailList')} value="thumbnail"><Tab sx={{ minWidth: 'auto' }} value="thumbnail" aria-label={t('thumbnailList')} aria-controls={`tab-panel-${id}`} icon={<ThumbnailListIcon />} /></Tooltip>
             </Tabs>
           </>
         )}
@@ -146,7 +154,7 @@ export class WindowSideBarCanvasPanel extends Component {
               onClick={showMultipart}
               endIcon={<ArrowForwardIcon />}
             >
-              <Typography className={classes.collectionNavigationButton}>
+              <Typography sx={{ textTransform: 'none' }}>
                 {WindowSideBarCanvasPanel.getUseableLabel(collection)}
               </Typography>
             </Button>
@@ -159,7 +167,6 @@ export class WindowSideBarCanvasPanel extends Component {
 }
 
 WindowSideBarCanvasPanel.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   collection: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   id: PropTypes.string.isRequired,
   sequenceId: PropTypes.string,
diff --git a/src/components/WindowSideBarCollectionPanel.js b/src/components/WindowSideBarCollectionPanel.js
index a6964ca77705542d3092fabc33881113f91abad8..f55a2dbdef728fbc29d65c9c04cb965644182325 100644
--- a/src/components/WindowSideBarCollectionPanel.js
+++ b/src/components/WindowSideBarCollectionPanel.js
@@ -1,14 +1,14 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import List from '@material-ui/core/List';
-import ListItem from '@material-ui/core/ListItem';
-import ListItemIcon from '@material-ui/core/ListItemIcon';
-import ListItemText from '@material-ui/core/ListItemText';
-import MenuList from '@material-ui/core/MenuList';
-import MenuItem from '@material-ui/core/MenuItem';
-import Typography from '@material-ui/core/Typography';
-import Skeleton from '@material-ui/lab/Skeleton';
-import ArrowUpwardIcon from '@material-ui/icons/ArrowUpwardSharp';
+import List from '@mui/material/List';
+import ListItem from '@mui/material/ListItem';
+import ListItemIcon from '@mui/material/ListItemIcon';
+import ListItemText from '@mui/material/ListItemText';
+import MenuList from '@mui/material/MenuList';
+import MenuItem from '@mui/material/MenuItem';
+import Typography from '@mui/material/Typography';
+import Skeleton from '@mui/material/Skeleton';
+import ArrowUpwardIcon from '@mui/icons-material/ArrowUpwardSharp';
 import CompanionWindow from '../containers/CompanionWindow';
 import IIIFThumbnail from '../containers/IIIFThumbnail';
 
@@ -20,7 +20,12 @@ function Item({
     <MenuItem
       alignItems="flex-start"
       button
+      divider
       component="li"
+      variant="multiline"
+      sx={{
+        paddingRight: 1,
+      }}
       {...otherProps}
     >
       { variant === 'thumbnail' && (
@@ -74,7 +79,6 @@ export class WindowSideBarCollectionPanel extends Component {
   render() {
     const {
       canvasNavigation,
-      classes,
       collectionPath,
       collection,
       id,
@@ -114,7 +118,7 @@ export class WindowSideBarCollectionPanel extends Component {
             )}
             <Typography variant="h6">
               { collection && WindowSideBarCollectionPanel.getUseableLabel(collection)}
-              { isFetching && <Skeleton className={classes.placeholder} variant="text" />}
+              { isFetching && <Skeleton variant="text" />}
             </Typography>
           </>
         )}
@@ -123,9 +127,9 @@ export class WindowSideBarCollectionPanel extends Component {
           { isFetching && (
             <MenuItem>
               <ListItemText>
-                <Skeleton className={classes.placeholder} variant="text" />
-                <Skeleton className={classes.placeholder} variant="text" />
-                <Skeleton className={classes.placeholder} variant="text" />
+                <Skeleton variant="text" />
+                <Skeleton variant="text" />
+                <Skeleton variant="text" />
               </ListItemText>
             </MenuItem>
           )}
@@ -144,7 +148,6 @@ export class WindowSideBarCollectionPanel extends Component {
                   canvasNavigation={canvasNavigation}
                   manifest={manifest}
                   variant={variant}
-                  className={classes.menuItem}
                   selected={manifestId === manifest.id}
                 />
               );
@@ -167,7 +170,6 @@ export class WindowSideBarCollectionPanel extends Component {
                   canvasNavigation={canvasNavigation}
                   manifest={manifest}
                   variant={variant}
-                  className={classes.menuItem}
                   selected={manifestId === manifest.id}
                 />
               );
@@ -184,7 +186,6 @@ WindowSideBarCollectionPanel.propTypes = {
     height: PropTypes.number,
     width: PropTypes.number,
   }).isRequired,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   collection: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   collectionPath: PropTypes.arrayOf(PropTypes.string),
   id: PropTypes.string.isRequired,
diff --git a/src/components/WindowSideBarInfoPanel.js b/src/components/WindowSideBarInfoPanel.js
index e2931f70e34426beac5cb635019dff157a79f99e..3261679503f289fa29caab0b4fb986e8bb963069 100644
--- a/src/components/WindowSideBarInfoPanel.js
+++ b/src/components/WindowSideBarInfoPanel.js
@@ -1,6 +1,7 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
 import CompanionWindow from '../containers/CompanionWindow';
+import { CompanionWindowSection } from './CompanionWindowSection';
 import CanvasInfo from '../containers/CanvasInfo';
 import LocalePicker from '../containers/LocalePicker';
 import ManifestInfo from '../containers/ManifestInfo';
@@ -21,7 +22,6 @@ export class WindowSideBarInfoPanel extends Component {
       windowId,
       id,
       canvasIds,
-      classes,
       collectionPath,
       t,
       locale,
@@ -49,7 +49,9 @@ export class WindowSideBarInfoPanel extends Component {
       >
         {
           canvasIds.map((canvasId, index) => (
-            <div key={canvasId} className={classes.section}>
+            <CompanionWindowSection
+              key={canvasId}
+            >
               <CanvasInfo
                 id={id}
                 canvasId={canvasId}
@@ -57,22 +59,22 @@ export class WindowSideBarInfoPanel extends Component {
                 totalSize={canvasIds.length}
                 windowId={windowId}
               />
-            </div>
+            </CompanionWindowSection>
           ))
         }
         { collectionPath.length > 0 && (
-          <div className={classes.section}>
+          <CompanionWindowSection>
             <CollectionInfo id={id} windowId={windowId} />
-          </div>
+          </CompanionWindowSection>
         )}
 
-        <div className={classes.section}>
+        <CompanionWindowSection>
           <ManifestInfo id={id} windowId={windowId} />
-        </div>
+        </CompanionWindowSection>
 
-        <div className={classes.section}>
+        <CompanionWindowSection>
           <ManifestRelatedLinks id={id} windowId={windowId} />
-        </div>
+        </CompanionWindowSection>
       </CompanionWindow>
     );
   }
@@ -81,7 +83,6 @@ export class WindowSideBarInfoPanel extends Component {
 WindowSideBarInfoPanel.propTypes = {
   availableLocales: PropTypes.arrayOf(PropTypes.string),
   canvasIds: PropTypes.arrayOf(PropTypes.string),
-  classes: PropTypes.objectOf(PropTypes.string),
   collectionPath: PropTypes.arrayOf(PropTypes.string),
   id: PropTypes.string.isRequired,
   locale: PropTypes.string,
@@ -94,7 +95,6 @@ WindowSideBarInfoPanel.propTypes = {
 WindowSideBarInfoPanel.defaultProps = {
   availableLocales: [],
   canvasIds: [],
-  classes: {},
   collectionPath: [],
   locale: '',
   setLocale: undefined,
diff --git a/src/components/WindowThumbnailSettings.js b/src/components/WindowThumbnailSettings.js
index 22b7eb57db316222e7a93a9e18b8301d138e7fb3..042355e4d01054086ec6cd21195670e166a06ffd 100644
--- a/src/components/WindowThumbnailSettings.js
+++ b/src/components/WindowThumbnailSettings.js
@@ -1,11 +1,25 @@
 import { Component } from 'react';
-import FormControlLabel from '@material-ui/core/FormControlLabel';
-import ListSubheader from '@material-ui/core/ListSubheader';
-import MenuItem from '@material-ui/core/MenuItem';
-import ThumbnailsOffIcon from '@material-ui/icons/CropDinSharp';
+import { styled } from '@mui/material/styles';
+import FormControlLabel from '@mui/material/FormControlLabel';
+import ListSubheader from '@mui/material/ListSubheader';
+import MenuItem from '@mui/material/MenuItem';
+import ThumbnailsOffIcon from '@mui/icons-material/CropDinSharp';
 import PropTypes from 'prop-types';
 import ThumbnailNavigationBottomIcon from './icons/ThumbnailNavigationBottomIcon';
 import ThumbnailNavigationRightIcon from './icons/ThumbnailNavigationRightIcon';
+
+const ThumbnailOption = styled(MenuItem, { name: 'WindowThumbnailSettings', slot: 'option' })(({ selected, theme }) => ({
+  '& .MuiFormControlLabel-label': {
+    borderBottom: '2px solid transparent',
+    ...(selected && {
+      borderBottomColor: theme.palette.secondary.main,
+    }),
+  },
+  backgroundColor: 'transparent !important',
+  color: selected ? theme.palette.secondary.main : undefined,
+  display: 'inline-block',
+}));
+
 /**
  *
  */
@@ -34,56 +48,53 @@ export class WindowThumbnailSettings extends Component {
    */
   render() {
     const {
-      classes, handleClose, t, thumbnailNavigationPosition, direction,
+      handleClose, t, thumbnailNavigationPosition, direction,
     } = this.props;
 
     return (
       <>
-        <ListSubheader role="presentation" disableSticky tabIndex="-1">{t('thumbnails')}</ListSubheader>
+        <ListSubheader role="presentation" disableSticky tabIndex={-1}>{t('thumbnails')}</ListSubheader>
 
-        <MenuItem className={classes.MenuItem} onClick={() => { this.handleChange('off'); handleClose(); }}>
+        <ThumbnailOption selected={thumbnailNavigationPosition === 'off'} onClick={() => { this.handleChange('off'); handleClose(); }}>
           <FormControlLabel
             value="off"
-            classes={{ label: thumbnailNavigationPosition === 'off' ? classes.selectedLabel : classes.label }}
             control={
-              <ThumbnailsOffIcon color={thumbnailNavigationPosition === 'off' ? 'secondary' : undefined} />
+              <ThumbnailsOffIcon color={thumbnailNavigationPosition === 'off' ? 'secondary' : undefined} fill="currentcolor" />
             }
             label={t('off')}
             labelPlacement="bottom"
           />
-        </MenuItem>
-        <MenuItem className={classes.MenuItem} onClick={() => { this.handleChange('far-bottom'); handleClose(); }}>
+        </ThumbnailOption>
+        <ThumbnailOption selected={thumbnailNavigationPosition === 'far-bottom'} onClick={() => { this.handleChange('far-bottom'); handleClose(); }}>
           <FormControlLabel
             value="far-bottom"
-            classes={{ label: thumbnailNavigationPosition === 'far-bottom' ? classes.selectedLabel : classes.label }}
             control={
-              <ThumbnailNavigationBottomIcon color={thumbnailNavigationPosition === 'far-bottom' ? 'secondary' : undefined} />
+              <ThumbnailNavigationBottomIcon color={thumbnailNavigationPosition === 'far-bottom' ? 'secondary' : undefined} fill="currentcolor" />
             }
             label={t('bottom')}
             labelPlacement="bottom"
           />
-        </MenuItem>
-        <MenuItem className={classes.MenuItem} onClick={() => { this.handleChange('far-right'); handleClose(); }}>
+        </ThumbnailOption>
+        <ThumbnailOption selected={thumbnailNavigationPosition === 'far-right'} onClick={() => { this.handleChange('far-right'); handleClose(); }}>
           <FormControlLabel
             value="far-right"
-            classes={{ label: thumbnailNavigationPosition === 'far-right' ? classes.selectedLabel : classes.label }}
             control={(
               <ThumbnailNavigationRightIcon
                 color={thumbnailNavigationPosition === 'far-right' ? 'secondary' : undefined}
+                fill="currentcolor"
                 style={direction === 'rtl' ? { transform: 'rotate(180deg)' } : {}}
               />
             )}
             label={t('right')}
             labelPlacement="bottom"
           />
-        </MenuItem>
+        </ThumbnailOption>
       </>
     );
   }
 }
 
 WindowThumbnailSettings.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   direction: PropTypes.string.isRequired,
   handleClose: PropTypes.func,
   setWindowThumbnailPosition: PropTypes.func.isRequired,
diff --git a/src/components/WindowTopBar.js b/src/components/WindowTopBar.js
index cf204b2f88c260c8f4a40c08ca594a209deb1de2..5e32f8cd0787303091ddba23f3fb1843cf6d40d6 100644
--- a/src/components/WindowTopBar.js
+++ b/src/components/WindowTopBar.js
@@ -1,9 +1,10 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import MenuIcon from '@material-ui/icons/MenuSharp';
-import CloseIcon from '@material-ui/icons/CloseSharp';
-import Toolbar from '@material-ui/core/Toolbar';
-import AppBar from '@material-ui/core/AppBar';
+import { styled } from '@mui/material/styles';
+import MenuIcon from '@mui/icons-material/MenuSharp';
+import CloseIcon from '@mui/icons-material/CloseSharp';
+import Toolbar from '@mui/material/Toolbar';
+import AppBar from '@mui/material/AppBar';
 import classNames from 'classnames';
 import WindowTopMenuButton from '../containers/WindowTopMenuButton';
 import WindowTopBarPluginArea from '../containers/WindowTopBarPluginArea';
@@ -15,6 +16,22 @@ import WindowMaxIcon from './icons/WindowMaxIcon';
 import WindowMinIcon from './icons/WindowMinIcon';
 import ns from '../config/css-ns';
 
+const Root = styled(AppBar, { name: 'WindowTopBar', slot: 'root' })(() => ({
+  zIndex: 1100,
+}));
+
+const StyledToolbar = styled(Toolbar, { name: 'WindowTopBar', slot: 'toolbar' })(({ ownerState, theme }) => ({
+  backgroundColor: theme.palette.shades?.main,
+  borderTop: '2px solid',
+  borderTopColor: ownerState?.focused ? theme.palette.primary.main : 'transparent',
+  minHeight: 32,
+  paddingLeft: theme.spacing(0.5),
+  paddingRight: theme.spacing(0.5),
+  ...(ownerState?.windowDraggable && {
+    cursor: 'move',
+  }),
+}));
+
 /**
  * WindowTopBar
  */
@@ -25,66 +42,61 @@ export class WindowTopBar extends Component {
    */
   render() {
     const {
-      removeWindow, windowId, classes, toggleWindowSideBar, t, windowDraggable,
-      maximizeWindow, maximized, minimizeWindow, focused, allowClose, allowMaximize,
+      removeWindow, windowId, toggleWindowSideBar, t,
+      maximizeWindow, maximized, minimizeWindow, allowClose, allowMaximize,
       focusWindow, allowFullscreen, allowTopMenuButton, allowWindowSideBar,
+      component,
     } = this.props;
 
     return (
-      <AppBar position="relative" color="default">
-        <nav aria-label={t('windowNavigation')}>
-          <Toolbar
-            disableGutters
-            onMouseDown={focusWindow}
-            className={classNames(
-              classes.windowTopBarStyle,
-              windowDraggable ? classes.windowTopBarStyleDraggable : null,
-              focused ? classes.focused : null,
-              ns('window-top-bar'),
-            )}
-            variant="dense"
-          >
-            {allowWindowSideBar && (
-              <MiradorMenuButton
-                aria-label={t('toggleWindowSideBar')}
-                onClick={toggleWindowSideBar}
-                className={ns('window-menu-btn')}
-              >
-                <MenuIcon />
-              </MiradorMenuButton>
-            )}
-            <WindowTopBarTitle
-              windowId={windowId}
-            />
-            {allowTopMenuButton && (
-              <WindowTopMenuButton windowId={windowId} className={ns('window-menu-btn')} />
-            )}
-            <WindowTopBarPluginArea windowId={windowId} />
-            <WindowTopBarPluginMenu windowId={windowId} />
-            {allowMaximize && (
-              <MiradorMenuButton
-                aria-label={(maximized ? t('minimizeWindow') : t('maximizeWindow'))}
-                className={classNames(ns('window-maximize'), ns('window-menu-btn'))}
-                onClick={(maximized ? minimizeWindow : maximizeWindow)}
-              >
-                {(maximized ? <WindowMinIcon /> : <WindowMaxIcon />)}
-              </MiradorMenuButton>
-            )}
-            {allowFullscreen && (
-              <FullScreenButton className={ns('window-menu-btn')} />
-            )}
-            {allowClose && (
-              <MiradorMenuButton
-                aria-label={t('closeWindow')}
-                className={classNames(ns('window-close'), ns('window-menu-btn'))}
-                onClick={removeWindow}
-              >
-                <CloseIcon />
-              </MiradorMenuButton>
-            )}
-          </Toolbar>
-        </nav>
-      </AppBar>
+      <Root component={component} aria-label={t('windowNavigation')} position="relative" color="default" enableColorOnDark>
+        <StyledToolbar
+          disableGutters
+          onMouseDown={focusWindow}
+          ownerState={this.props}
+          className={classNames(ns('window-top-bar'))}
+          variant="dense"
+        >
+          {allowWindowSideBar && (
+            <MiradorMenuButton
+              aria-label={t('toggleWindowSideBar')}
+              onClick={toggleWindowSideBar}
+              className={ns('window-menu-btn')}
+            >
+              <MenuIcon />
+            </MiradorMenuButton>
+          )}
+          <WindowTopBarTitle
+            windowId={windowId}
+          />
+          {allowTopMenuButton && (
+            <WindowTopMenuButton windowId={windowId} className={ns('window-menu-btn')} />
+          )}
+          <WindowTopBarPluginArea windowId={windowId} />
+          <WindowTopBarPluginMenu windowId={windowId} />
+          {allowMaximize && (
+            <MiradorMenuButton
+              aria-label={(maximized ? t('minimizeWindow') : t('maximizeWindow'))}
+              className={classNames(ns('window-maximize'), ns('window-menu-btn'))}
+              onClick={(maximized ? minimizeWindow : maximizeWindow)}
+            >
+              {(maximized ? <WindowMinIcon /> : <WindowMaxIcon />)}
+            </MiradorMenuButton>
+          )}
+          {allowFullscreen && (
+            <FullScreenButton className={ns('window-menu-btn')} />
+          )}
+          {allowClose && (
+            <MiradorMenuButton
+              aria-label={t('closeWindow')}
+              className={classNames(ns('window-close'), ns('window-menu-btn'))}
+              onClick={removeWindow}
+            >
+              <CloseIcon />
+            </MiradorMenuButton>
+          )}
+        </StyledToolbar>
+      </Root>
     );
   }
 }
@@ -95,8 +107,8 @@ WindowTopBar.propTypes = {
   allowMaximize: PropTypes.bool,
   allowTopMenuButton: PropTypes.bool,
   allowWindowSideBar: PropTypes.bool,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
-  focused: PropTypes.bool,
+  component: PropTypes.elementType,
+  focused: PropTypes.bool, // eslint-disable-line react/no-unused-prop-types
   focusWindow: PropTypes.func,
   maximized: PropTypes.bool,
   maximizeWindow: PropTypes.func,
@@ -104,7 +116,7 @@ WindowTopBar.propTypes = {
   removeWindow: PropTypes.func.isRequired,
   t: PropTypes.func,
   toggleWindowSideBar: PropTypes.func.isRequired,
-  windowDraggable: PropTypes.bool,
+  windowDraggable: PropTypes.bool, // eslint-disable-line react/no-unused-prop-types
   windowId: PropTypes.string.isRequired,
 };
 
@@ -114,6 +126,7 @@ WindowTopBar.defaultProps = {
   allowMaximize: true,
   allowTopMenuButton: true,
   allowWindowSideBar: true,
+  component: 'nav',
   focused: false,
   focusWindow: () => {},
   maximized: false,
diff --git a/src/components/WindowTopBarPluginMenu.js b/src/components/WindowTopBarPluginMenu.js
index 78f95a73ec5566fab2d4565c34d86b3ce2a0d732..972cbf544b6c32b1aa87f2d8fcfff1e770ef0b54 100644
--- a/src/components/WindowTopBarPluginMenu.js
+++ b/src/components/WindowTopBarPluginMenu.js
@@ -1,7 +1,7 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import MoreVertIcon from '@material-ui/icons/MoreVertSharp';
-import Menu from '@material-ui/core/Menu';
+import MoreVertIcon from '@mui/icons-material/MoreVertSharp';
+import Menu from '@mui/material/Menu';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 import { PluginHook } from './PluginHook';
 
@@ -47,7 +47,7 @@ export class WindowTopBarPluginMenu extends Component {
    */
   render() {
     const {
-      classes, container, PluginComponents, t, windowId, menuIcon,
+      container, PluginComponents, t, windowId, menuIcon,
     } = this.props;
     const { anchorEl, open } = this.state;
     const windowPluginMenuId = `window-plugin-menu_${windowId}`;
@@ -59,7 +59,7 @@ export class WindowTopBarPluginMenu extends Component {
           aria-haspopup="true"
           aria-label={t('windowPluginMenu')}
           aria-owns={open ? windowPluginMenuId : undefined}
-          className={open ? classes.ctrlBtnSelected : null}
+          selected={open}
           onClick={this.handleMenuClick}
         >
           {menuIcon}
@@ -77,7 +77,6 @@ export class WindowTopBarPluginMenu extends Component {
             horizontal: 'right',
             vertical: 'top',
           }}
-          getContentAnchorEl={null}
           open={open}
           onClose={() => this.handleMenuClose()}
         >
@@ -90,9 +89,6 @@ export class WindowTopBarPluginMenu extends Component {
 
 WindowTopBarPluginMenu.propTypes = {
   anchorEl: PropTypes.object, // eslint-disable-line react/forbid-prop-types
-  classes: PropTypes.shape({
-    ctrlBtnSelected: PropTypes.string,
-  }),
   container: PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
   menuIcon: PropTypes.element,
   open: PropTypes.bool,
@@ -105,7 +101,6 @@ WindowTopBarPluginMenu.propTypes = {
 
 WindowTopBarPluginMenu.defaultProps = {
   anchorEl: null,
-  classes: {},
   container: null,
   menuIcon: <MoreVertIcon />,
   open: false,
diff --git a/src/components/WindowTopBarTitle.js b/src/components/WindowTopBarTitle.js
index b47f00c2c2e03433cf198724553503e38fecb5ec..5c91250e12861c7e2a4426e214fdc5499e663bba 100644
--- a/src/components/WindowTopBarTitle.js
+++ b/src/components/WindowTopBarTitle.js
@@ -1,9 +1,21 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Typography from '@material-ui/core/Typography';
-import Skeleton from '@material-ui/lab/Skeleton';
-import ErrorIcon from '@material-ui/icons/ErrorOutlineSharp';
+import { styled } from '@mui/material/styles';
+import Typography from '@mui/material/Typography';
+import Skeleton from '@mui/material/Skeleton';
+import ErrorIcon from '@mui/icons-material/ErrorOutlineSharp';
 
+const StyledTitleTypography = styled(TitleTypography)(({ theme }) => ({
+  ...theme.typography.h6,
+  flexGrow: 1,
+  paddingLeft: theme.spacing(0.5),
+}));
+
+const StyledTitle = styled('div')(({ theme }) => ({
+  ...theme.typography.h6,
+  flexGrow: 1,
+  paddingLeft: theme.spacing(0.5),
+}));
 /** */
 function TitleTypography({ children, ...props }) {
   return (
@@ -27,32 +39,32 @@ export class WindowTopBarTitle extends Component {
    */
   render() {
     const {
-      classes, error, hideWindowTitle, isFetching, manifestTitle,
+      error, hideWindowTitle, isFetching, manifestTitle,
     } = this.props;
 
     let title = null;
     if (isFetching) {
       title = (
-        <TitleTypography className={classes.title}>
+        <StyledTitleTypography>
           <Skeleton variant="text" />
-        </TitleTypography>
+        </StyledTitleTypography>
       );
     } else if (error) {
       title = (
         <>
           <ErrorIcon color="error" />
-          <TitleTypography color="textSecondary" className={classes.title}>
+          <StyledTitleTypography color="textSecondary">
             {error}
-          </TitleTypography>
+          </StyledTitleTypography>
         </>
       );
     } else if (hideWindowTitle) {
-      title = (<div className={classes.title} />);
+      title = (<StyledTitle />);
     } else {
       title = (
-        <TitleTypography className={classes.title}>
+        <StyledTitleTypography>
           {manifestTitle}
-        </TitleTypography>
+        </StyledTitleTypography>
       );
     }
     return title;
@@ -60,7 +72,6 @@ export class WindowTopBarTitle extends Component {
 }
 
 WindowTopBarTitle.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   error: PropTypes.string,
   hideWindowTitle: PropTypes.bool,
   isFetching: PropTypes.bool,
diff --git a/src/components/WindowTopMenu.js b/src/components/WindowTopMenu.js
index d978876a33debb3f9ea428b398720c1dc21094f4..feb45377bd37aafa51e484b40216faf69c2d2340 100644
--- a/src/components/WindowTopMenu.js
+++ b/src/components/WindowTopMenu.js
@@ -1,6 +1,6 @@
 import { Component } from 'react';
-import Menu from '@material-ui/core//Menu';
-import ListSubheader from '@material-ui/core/ListSubheader';
+import Menu from '@mui/material//Menu';
+import ListSubheader from '@mui/material/ListSubheader';
 import PropTypes from 'prop-types';
 import WindowThumbnailSettings from '../containers/WindowThumbnailSettings';
 import WindowViewSettings from '../containers/WindowViewSettings';
@@ -11,7 +11,7 @@ function PluginHookWithHeader(props) {
   const { PluginComponents, t } = props; // eslint-disable-line react/prop-types
   return PluginComponents ? (
     <>
-      <ListSubheader role="presentation" disableSticky tabIndex="-1">{t('windowPluginButtons')}</ListSubheader>
+      <ListSubheader role="presentation" disableSticky tabIndex={-1}>{t('windowPluginButtons')}</ListSubheader>
       <PluginHook {...props} />
     </>
   ) : null;
@@ -47,7 +47,6 @@ export class WindowTopMenu extends Component {
           onExit: toggleDraggingEnabled,
         }}
         orientation="horizontal"
-        getContentAnchorEl={null}
         anchorEl={anchorEl}
         open={open}
       >
diff --git a/src/components/WindowTopMenuButton.js b/src/components/WindowTopMenuButton.js
index ca9ab8db0109377d74a17f229cbf40a25bd40ffb..e48bd84d2c3c5aa0d6fbbab209a1d1f28be262d8 100644
--- a/src/components/WindowTopMenuButton.js
+++ b/src/components/WindowTopMenuButton.js
@@ -1,6 +1,5 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import classNames from 'classnames';
 import WindowTopMenu from '../containers/WindowTopMenu';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 import WindowOptionsIcon from './icons/WindowOptionsIcon';
@@ -47,7 +46,7 @@ export class WindowTopMenuButton extends Component {
    */
   render() {
     const {
-      classes, className, t, windowId,
+      classes, t, windowId,
     } = this.props;
     const { open, anchorEl } = this.state;
     const menuId = `window-menu_${windowId}`;
@@ -57,7 +56,8 @@ export class WindowTopMenuButton extends Component {
           aria-haspopup="true"
           aria-label={t('windowMenu')}
           aria-owns={open ? menuId : undefined}
-          className={classNames(className, open ? classes.ctrlBtnSelected : null)}
+          className={open ? classes.ctrlBtnSelected : undefined}
+          selected={open}
           onClick={this.handleMenuClick}
         >
           <WindowOptionsIcon />
@@ -75,13 +75,12 @@ export class WindowTopMenuButton extends Component {
 }
 
 WindowTopMenuButton.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
-  className: PropTypes.string,
+  classes: PropTypes.objectOf(PropTypes.string),
   t: PropTypes.func,
   windowId: PropTypes.string.isRequired,
 };
 
 WindowTopMenuButton.defaultProps = {
-  className: '',
+  classes: {},
   t: key => key,
 };
diff --git a/src/components/WindowViewSettings.js b/src/components/WindowViewSettings.js
index 90c56b823269cf733b54c88132b4cb732467883e..e693b2ffcdc62caab53200c3178d6597257169ea 100644
--- a/src/components/WindowViewSettings.js
+++ b/src/components/WindowViewSettings.js
@@ -1,13 +1,26 @@
 import { Component } from 'react';
-import FormControlLabel from '@material-ui/core/FormControlLabel';
-import MenuItem from '@material-ui/core/MenuItem';
-import ListSubheader from '@material-ui/core/ListSubheader';
-import SingleIcon from '@material-ui/icons/CropOriginalSharp';
-import ScrollViewIcon from '@material-ui/icons/ViewColumn';
+import { styled } from '@mui/material/styles';
+import FormControlLabel from '@mui/material/FormControlLabel';
+import MenuItem from '@mui/material/MenuItem';
+import ListSubheader from '@mui/material/ListSubheader';
+import SingleIcon from '@mui/icons-material/CropOriginalSharp';
+import ScrollViewIcon from '@mui/icons-material/ViewColumn';
 import PropTypes from 'prop-types';
 import BookViewIcon from './icons/BookViewIcon';
 import GalleryViewIcon from './icons/GalleryViewIcon';
 
+const ViewOption = styled(MenuItem, { name: 'WindowViewSettings', slot: 'option' })(({ selected, theme }) => ({
+  '& .MuiFormControlLabel-label': {
+    borderBottom: '2px solid transparent',
+    ...(selected && {
+      borderBottomColor: theme.palette.secondary.main,
+    }),
+  },
+  backgroundColor: 'transparent !important',
+  color: selected ? theme.palette.secondary.main : undefined,
+  display: 'inline-block',
+}));
+
 /**
  *
  */
@@ -36,7 +49,7 @@ export class WindowViewSettings extends Component {
    */
   render() {
     const {
-      classes, handleClose, t, windowViewType, viewTypes,
+      handleClose, t, windowViewType, viewTypes,
     } = this.props;
 
     const iconMap = {
@@ -49,26 +62,25 @@ export class WindowViewSettings extends Component {
     /** Suspiciously similar to a component, yet if it is invoked through JSX
         none of the click handlers work? */
     const menuItem = ({ value, Icon }) => (
-      <MenuItem
+      <ViewOption
+        selected={windowViewType === value}
         key={value}
-        className={classes.MenuItem}
         autoFocus={windowViewType === value}
         onClick={() => { this.handleChange(value); handleClose(); }}
       >
         <FormControlLabel
           value={value}
-          classes={{ label: windowViewType === value ? classes.selectedLabel : classes.label }}
-          control={<Icon color={windowViewType === value ? 'secondary' : undefined} />}
+          control={<Icon fill="currentcolor" color={windowViewType === value ? 'secondary' : undefined} />}
           label={t(value)}
           labelPlacement="bottom"
         />
-      </MenuItem>
+      </ViewOption>
     );
 
     if (viewTypes.length === 0) return null;
     return (
       <>
-        <ListSubheader role="presentation" disableSticky tabIndex="-1">{t('view')}</ListSubheader>
+        <ListSubheader role="presentation" disableSticky tabIndex={-1}>{t('view')}</ListSubheader>
         { viewTypes.map(value => menuItem({ Icon: iconMap[value], value })) }
       </>
     );
@@ -76,7 +88,6 @@ export class WindowViewSettings extends Component {
 }
 
 WindowViewSettings.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   handleClose: PropTypes.func,
   setWindowViewType: PropTypes.func.isRequired,
   t: PropTypes.func,
diff --git a/src/components/Workspace.js b/src/components/Workspace.js
index f99f61d4e4351078b811d874dba828aca7d7ad6f..c94f8a30b3fc1eb1550ff0fe3a90211bedc14c5b 100644
--- a/src/components/Workspace.js
+++ b/src/components/Workspace.js
@@ -1,14 +1,22 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import classNames from 'classnames';
-import Grid from '@material-ui/core/Grid';
-import Typography from '@material-ui/core/Typography';
+import Grid from '@mui/material/Grid';
+import Typography from '@mui/material/Typography';
+import { visuallyHidden } from '@mui/utils';
 import Window from '../containers/Window';
 import WorkspaceMosaic from '../containers/WorkspaceMosaic';
 import WorkspaceElastic from '../containers/WorkspaceElastic';
 import ns from '../config/css-ns';
 import { IIIFDropTarget } from './IIIFDropTarget';
 
+const Root = styled('div', { name: 'Workspace', slot: 'root' })(() => ({
+  height: '100%',
+  position: 'relative',
+  width: '100%',
+}));
+
 /**
  * Represents a work area that contains any number of windows
  * @memberof Workspace
@@ -62,26 +70,28 @@ export class Workspace extends Component {
     const { t } = this.props;
 
     return (
-      <Grid
-        alignItems="center"
-        container
-        style={{
-          height: '100%',
-        }}
-      >
+      <Root>
         <Grid
-          xs={12}
-          item
+          alignItems="center"
+          container
+          style={{
+            height: '100%',
+          }}
         >
-          <Typography
-            variant="h1"
-            component="div"
-            align="center"
+          <Grid
+            xs={12}
+            item
           >
-            {t('welcome')}
-          </Typography>
+            <Typography
+              variant="h1"
+              component="div"
+              align="center"
+            >
+              {t('welcome')}
+            </Typography>
+          </Grid>
         </Grid>
-      </Grid>
+      </Root>
     );
   }
 
@@ -107,23 +117,21 @@ export class Workspace extends Component {
    * render
    */
   render() {
-    const { classes, isWorkspaceControlPanelVisible, t } = this.props;
+    const { t } = this.props;
 
     return (
       <IIIFDropTarget onDrop={this.handleDrop}>
-        <div
+        <Root
+          ownerState={this.props}
           className={
             classNames(
               ns('workspace-viewport'),
-              (isWorkspaceControlPanelVisible && ns('workspace-with-control-panel')),
-              (isWorkspaceControlPanelVisible && classes.workspaceWithControlPanel),
-              classes.workspaceViewport,
             )
           }
         >
-          <Typography variant="srOnly" component="h1">{t('miradorViewer')}</Typography>
+          <Typography style={visuallyHidden} component="h1">{t('miradorViewer')}</Typography>
           {this.workspaceByType()}
-        </div>
+        </Root>
       </IIIFDropTarget>
     );
   }
@@ -132,8 +140,6 @@ export class Workspace extends Component {
 Workspace.propTypes = {
   addWindow: PropTypes.func,
   allowNewWindows: PropTypes.bool,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
-  isWorkspaceControlPanelVisible: PropTypes.bool.isRequired,
   maximizedWindowIds: PropTypes.arrayOf(PropTypes.string),
   t: PropTypes.func.isRequired,
   windowIds: PropTypes.arrayOf(PropTypes.string),
diff --git a/src/components/WorkspaceAdd.js b/src/components/WorkspaceAdd.js
index 172c8d3474970c769e39084dbde0bad3b43c846f..6e744878c40c1503314274002e1fe6cca2c6de97 100644
--- a/src/components/WorkspaceAdd.js
+++ b/src/components/WorkspaceAdd.js
@@ -1,16 +1,18 @@
 import { createRef, Component } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import classNames from 'classnames';
-import AddIcon from '@material-ui/icons/AddSharp';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMoreSharp';
-import AppBar from '@material-ui/core/AppBar';
-import Drawer from '@material-ui/core/Drawer';
-import Grid from '@material-ui/core/Grid';
-import Fab from '@material-ui/core/Fab';
-import List from '@material-ui/core/List';
-import Paper from '@material-ui/core/Paper';
-import Toolbar from '@material-ui/core/Toolbar';
-import Typography from '@material-ui/core/Typography';
+import AddIcon from '@mui/icons-material/AddSharp';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMoreSharp';
+import AppBar from '@mui/material/AppBar';
+import Drawer from '@mui/material/Drawer';
+import Grid from '@mui/material/Grid';
+import Fab from '@mui/material/Fab';
+import List from '@mui/material/List';
+import Paper from '@mui/material/Paper';
+import Toolbar from '@mui/material/Toolbar';
+import Typography from '@mui/material/Typography';
+import { visuallyHidden } from '@mui/utils';
 import ns from '../config/css-ns';
 import ManifestForm from '../containers/ManifestForm';
 import ManifestListItem from '../containers/ManifestListItem';
@@ -18,6 +20,17 @@ import MiradorMenuButton from '../containers/MiradorMenuButton';
 import { IIIFDropTarget } from './IIIFDropTarget';
 import { PluginHook } from './PluginHook';
 
+const StyledWorkspaceAdd = styled('div')(() => ({
+  boxSizing: 'border-box',
+  height: '100%',
+  overflowX: 'hidden',
+  overflowY: 'auto',
+}));
+
+const StyledMiradorMenuButton = styled(MiradorMenuButton)(() => ({
+  marginLeft: -12,
+  marginRight: 20,
+}));
 /**
  * An area for managing manifests and adding them to workspace
  * @memberof Workspace
@@ -75,7 +88,7 @@ export class WorkspaceAdd extends Component {
    */
   render() {
     const {
-      catalog, setWorkspaceAddVisibility, t, classes,
+      catalog, setWorkspaceAddVisibility, t,
     } = this.props;
     const { addResourcesOpen } = this.state;
 
@@ -91,7 +104,7 @@ export class WorkspaceAdd extends Component {
 
     return (
       <IIIFDropTarget onDrop={this.handleDrop}>
-        <div ref={this.ref} className={classNames(ns('workspace-add'), classes.workspaceAdd)}>
+        <StyledWorkspaceAdd ref={this.ref} className={classNames(ns('workspace-add'))}>
           {catalog.length < 1 ? (
             <Grid
               alignItems="center"
@@ -114,8 +127,8 @@ export class WorkspaceAdd extends Component {
               </Grid>
             </Grid>
           ) : (
-            <Paper className={classes.list}>
-              <Typography variant="srOnly" component="h1">{t('miradorResources')}</Typography>
+            <Paper sx={{ margin: 2 }}>
+              <Typography style={visuallyHidden} component="h1">{t('miradorResources')}</Typography>
               <PluginHook {...this.props} />
               <List disablePadding>
                 {manifestList}
@@ -125,7 +138,12 @@ export class WorkspaceAdd extends Component {
           <Fab
             variant="extended"
             disabled={addResourcesOpen}
-            className={classNames(classes.fab, ns('add-resource-button'))}
+            sx={(theme) => ({
+              bottom: theme.spacing(2),
+              position: 'absolute',
+              right: theme.spacing(2),
+            })}
+            className={classNames(ns('add-resource-button'))}
             color="primary"
             onClick={() => (this.setAddResourcesVisibility(true))}
           >
@@ -134,10 +152,18 @@ export class WorkspaceAdd extends Component {
           </Fab>
 
           <Drawer
-            className={classNames({
-              [classes.displayNone]: !addResourcesOpen,
+            sx={theme => ({
+              '.MuiDrawer-paper': {
+                borderTop: '0',
+                left: '0',
+                [theme.breakpoints.up('sm')]: {
+                  left: '65px',
+                },
+              },
+              ...(!addResourcesOpen && {
+                display: 'none',
+              }),
             })}
-            classes={{ paper: classes.paper }}
             variant="persistent"
             anchor="bottom"
             open={addResourcesOpen}
@@ -148,18 +174,25 @@ export class WorkspaceAdd extends Component {
             }}
           >
             <Paper
-              className={classes.form}
+              sx={{
+                left: '0',
+                marginTop: 6,
+                paddingBottom: 2,
+                paddingLeft: { sm: 3, xs: 2 },
+                paddingRight: { sm: 3, xs: 2 },
+                paddingTop: 2,
+                right: '0',
+              }}
             >
-              <AppBar position="absolute" color="primary" onClick={() => (this.setAddResourcesVisibility(false))}>
+              <AppBar position="absolute" color="primary" enableColorOnDark onClick={() => (this.setAddResourcesVisibility(false))}>
                 <Toolbar variant="dense">
-                  <MiradorMenuButton
+                  <StyledMiradorMenuButton
                     aria-label={t('closeAddResourceForm')}
-                    className={classes.menuButton}
                     color="inherit"
                   >
                     <ExpandMoreIcon />
-                  </MiradorMenuButton>
-                  <Typography variant="h2" noWrap color="inherit" className={classes.typographyBody}>
+                  </StyledMiradorMenuButton>
+                  <Typography variant="h2" noWrap color="inherit" sx={{ flexGrow: 1 }}>
                     {t('addResource')}
                   </Typography>
                 </Toolbar>
@@ -171,7 +204,7 @@ export class WorkspaceAdd extends Component {
               />
             </Paper>
           </Drawer>
-        </div>
+        </StyledWorkspaceAdd>
       </IIIFDropTarget>
     );
   }
@@ -183,7 +216,6 @@ WorkspaceAdd.propTypes = {
     manifestId: PropTypes.string.isRequired,
     provider: PropTypes.string,
   })),
-  classes: PropTypes.objectOf(PropTypes.string),
   setWorkspaceAddVisibility: PropTypes.func.isRequired,
   t: PropTypes.func,
 };
@@ -191,6 +223,5 @@ WorkspaceAdd.propTypes = {
 WorkspaceAdd.defaultProps = {
   addResource: () => {},
   catalog: [],
-  classes: {},
   t: key => key,
 };
diff --git a/src/components/WorkspaceAddButton.js b/src/components/WorkspaceAddButton.js
index b80ec8136911b0e8a34a16b74ab6c748de3ce6f2..b50679226e4082364041ce4eb77c73b56d1579ca 100644
--- a/src/components/WorkspaceAddButton.js
+++ b/src/components/WorkspaceAddButton.js
@@ -1,9 +1,14 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import Fab from '@material-ui/core/Fab';
-import Tooltip from '@material-ui/core/Tooltip';
-import AddIcon from '@material-ui/icons/AddSharp';
-import CloseIcon from '@material-ui/icons/CloseSharp';
+import Fab from '@mui/material/Fab';
+import Tooltip from '@mui/material/Tooltip';
+import AddIcon from '@mui/icons-material/AddSharp';
+import CloseIcon from '@mui/icons-material/CloseSharp';
+import { styled } from '@mui/material/styles';
+
+const Root = styled(Fab, { name: 'WorkspaceAddButton', slot: 'root' })(({ theme }) => ({
+  marginBottom: theme.spacing(1),
+}));
 
 /**
  */
@@ -14,22 +19,19 @@ export class WorkspaceAddButton extends Component {
    */
   render() {
     const {
-      classes, t, setWorkspaceAddVisibility, isWorkspaceAddVisible, useExtendedFab,
+      t, setWorkspaceAddVisibility, isWorkspaceAddVisible, useExtendedFab,
     } = this.props;
     return (
       <Tooltip title={isWorkspaceAddVisible ? t('closeAddResourceMenu') : t('addResource')}>
-        <Fab
+        <Root
           size="medium"
           color="primary"
           id="addBtn"
-          disableRipple
           aria-label={
             isWorkspaceAddVisible
               ? t('closeAddResourceMenu')
               : ((useExtendedFab && t('startHere')) || t('addResource'))
           }
-          className={classes.fab}
-          classes={{ primary: classes.fabPrimary, secondary: classes.fabSecondary }}
           variant={useExtendedFab ? 'extended' : 'circular'}
           onClick={() => { setWorkspaceAddVisibility(!isWorkspaceAddVisible); }}
         >
@@ -39,14 +41,13 @@ export class WorkspaceAddButton extends Component {
               : <AddIcon />
           }
           { useExtendedFab && t('startHere') }
-        </Fab>
+        </Root>
       </Tooltip>
     );
   }
 }
 
 WorkspaceAddButton.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   isWorkspaceAddVisible: PropTypes.bool,
   setWorkspaceAddVisibility: PropTypes.func.isRequired,
   t: PropTypes.func,
diff --git a/src/components/WorkspaceArea.js b/src/components/WorkspaceArea.js
index b6e2d10ba71a2fff9a5744cb89acb484e76acdb5..16200f8d817f18c107737aa30cdf3f7703f082fc 100644
--- a/src/components/WorkspaceArea.js
+++ b/src/components/WorkspaceArea.js
@@ -1,6 +1,6 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import classNames from 'classnames';
+import { styled, lighten, darken } from '@mui/material/styles';
 import ErrorDialog from '../containers/ErrorDialog';
 import WorkspaceControlPanel from '../containers/WorkspaceControlPanel';
 import Workspace from '../containers/Workspace';
@@ -8,6 +8,29 @@ import WorkspaceAdd from '../containers/WorkspaceAdd';
 import BackgroundPluginArea from '../containers/BackgroundPluginArea';
 import ns from '../config/css-ns';
 
+const Root = styled('div', { name: 'WorkspaceArea', slot: 'root' })(({ theme }) => {
+  const getBackgroundColor = theme.palette.mode === 'light' ? darken : lighten;
+
+  return {
+    background: getBackgroundColor(theme.palette.shades.light, 0.1),
+    bottom: 0,
+    display: 'flex',
+    flexDirection: 'column',
+    left: 0,
+    position: 'absolute',
+    right: 0,
+    top: 0,
+    [theme.breakpoints.up('sm')]: {
+      flexDirection: 'row',
+    },
+  };
+});
+
+const ViewerArea = styled('main', { name: 'WorkspaceArea', slot: 'viewer' })(() => ({
+  flexGrow: 1,
+  position: 'relative',
+}));
+
 /**
  * This is the top level Mirador component.
  * @prop {Object} manifests
@@ -20,7 +43,6 @@ export class WorkspaceArea extends Component {
   render() {
     const {
       areaRef,
-      classes,
       controlPanelVariant,
       isWorkspaceAddVisible,
       isWorkspaceControlPanelVisible,
@@ -29,13 +51,13 @@ export class WorkspaceArea extends Component {
     } = this.props;
 
     return (
-      <>
+      <Root ownerState={this.props}>
         {
           isWorkspaceControlPanelVisible
             && <WorkspaceControlPanel variant={controlPanelVariant} />
         }
-        <main
-          className={classNames(classes.viewer, ns('viewer'))}
+        <ViewerArea
+          className={ns('viewer')}
           lang={lang}
           aria-label={t('workspace')}
           {...(areaRef ? { ref: areaRef } : {})}
@@ -47,15 +69,14 @@ export class WorkspaceArea extends Component {
           }
           <ErrorDialog />
           <BackgroundPluginArea />
-        </main>
-      </>
+        </ViewerArea>
+      </Root>
     );
   }
 }
 
 WorkspaceArea.propTypes = {
   areaRef: PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   controlPanelVariant: PropTypes.string,
   isWorkspaceAddVisible: PropTypes.bool,
   isWorkspaceControlPanelVisible: PropTypes.bool.isRequired,
diff --git a/src/components/WorkspaceControlPanel.js b/src/components/WorkspaceControlPanel.js
index 376558285d3ac7154425a555690f1a08220f5fc0..1331341330cc8ff29e1199eb1f21f98ad6b2b325 100644
--- a/src/components/WorkspaceControlPanel.js
+++ b/src/components/WorkspaceControlPanel.js
@@ -1,13 +1,59 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import classNames from 'classnames';
-import AppBar from '@material-ui/core/AppBar';
-import Toolbar from '@material-ui/core/Toolbar';
+import AppBar from '@mui/material/AppBar';
+import Toolbar from '@mui/material/Toolbar';
 import WorkspaceAddButton from '../containers/WorkspaceAddButton';
 import WorkspaceControlPanelButtons from '../containers/WorkspaceControlPanelButtons';
 import Branding from '../containers/Branding';
 import ns from '../config/css-ns';
 
+const Root = styled(AppBar, { name: 'WorkspaceControlPanel', slot: 'root' })(({ ownerState, theme }) => ({
+  display: 'flex',
+  height: 64,
+  padding: theme.spacing(1),
+  paddingBottom: 0,
+  position: 'relative',
+  [theme.breakpoints.up('sm')]: {
+    height: 'auto',
+    width: ownerState.variant === 'wide' ? 'auto' : 64,
+  },
+  ...(ownerState.variant === 'wide' && {
+    width: 'auto',
+  }),
+}));
+
+const StyledToolbar = styled(Toolbar, { name: 'WorkspaceControlPanel', slot: 'toolbar' })(({ theme }) => ({
+  display: 'flex',
+  flexGrow: 1,
+  justifyContent: 'space-between',
+  [theme.breakpoints.up('sm')]: {
+    flexDirection: 'column',
+    justifyContent: 'flex-start',
+    minHeight: 0,
+  },
+}));
+
+const StyledWorkspaceButtons = styled('div', { name: 'WorkspaceControlPanel', slot: 'buttonArea' })(({ theme }) => ({
+  [theme.breakpoints.up('sm')]: {
+    display: 'flex',
+    flexDirection: 'column',
+    gap: theme.spacing(2),
+    marginBottom: theme.spacing(1),
+    marginTop: theme.spacing(1),
+  },
+}));
+
+const StyledBranding = styled(Branding, { name: 'WorkspaceControlPanel', slot: 'branding' })(({ theme }) => ({
+  [theme.breakpoints.up('xs')]: {
+    display: 'none',
+  },
+  [theme.breakpoints.up('sm')]: {
+    display: 'flex',
+  },
+}));
+
 /**
  * Provides the panel responsible for controlling the entire workspace
  */
@@ -17,34 +63,36 @@ export class WorkspaceControlPanel extends Component {
    * @return {String} - HTML markup for the component
    */
   render() {
-    const { classes, t, variant } = this.props;
+    const { t, variant } = this.props;
     return (
-      <AppBar
-        className={classNames(classes.root, ns('workspace-control-panel'), variant === 'wide' ? classes.wide : null)}
+      <Root
+        ownerState={this.props}
+        className={classNames(ns('workspace-control-panel'))}
         color="default"
+        enableColorOnDark
         position="absolute"
         component="nav"
         aria-label={t('workspaceNavigation')}
       >
-        <Toolbar disableGutters className={classes.toolbar}>
+        <StyledToolbar
+          disableGutters
+        >
           <WorkspaceAddButton />
-          <div className={classes.workspaceButtons}>
+          <StyledWorkspaceButtons>
             <WorkspaceControlPanelButtons />
-          </div>
-        </Toolbar>
-        <Branding className={classes.branding} t={t} variant={variant} />
-      </AppBar>
+          </StyledWorkspaceButtons>
+        </StyledToolbar>
+        <StyledBranding t={t} variant={variant} />
+      </Root>
     );
   }
 }
 
 WorkspaceControlPanel.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string),
   t: PropTypes.func.isRequired,
   variant: PropTypes.oneOf(['default', 'wide']),
 };
 
 WorkspaceControlPanel.defaultProps = {
-  classes: {},
   variant: 'default',
 };
diff --git a/src/components/WorkspaceControlPanelButtons.js b/src/components/WorkspaceControlPanelButtons.js
index b07adfc54298955b08cbfc1ffd60299bbad125f9..34cbf840ea9a1810a90e13bbbae9776b684cfea5 100644
--- a/src/components/WorkspaceControlPanelButtons.js
+++ b/src/components/WorkspaceControlPanelButtons.js
@@ -1,5 +1,4 @@
 import { Component } from 'react';
-import PropTypes from 'prop-types';
 import FullScreenButton from '../containers/FullScreenButton';
 import WorkspaceMenuButton from '../containers/WorkspaceMenuButton';
 import WorkspaceOptionsButton from '../containers/WorkspaceOptionsButton';
@@ -16,23 +15,14 @@ export class WorkspaceControlPanelButtons extends Component {
    * @return {type}  description
    */
   render() {
-    const { classes } = this.props;
     return (
       <>
         <WindowListButton />
         <WorkspaceMenuButton />
         <WorkspaceOptionsButton />
-        <FullScreenButton className={classes.ctrlBtn} />
+        <FullScreenButton />
         <PluginHook {...this.props} />
       </>
     );
   }
 }
-
-WorkspaceControlPanelButtons.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string),
-};
-
-WorkspaceControlPanelButtons.defaultProps = {
-  classes: {},
-};
diff --git a/src/components/WorkspaceDialog.js b/src/components/WorkspaceDialog.js
new file mode 100644
index 0000000000000000000000000000000000000000..0928db6502f527924127ff0032422de6fa8aed1b
--- /dev/null
+++ b/src/components/WorkspaceDialog.js
@@ -0,0 +1,13 @@
+import {
+  Dialog,
+} from '@mui/material';
+import { styled } from '@mui/material/styles';
+
+export const WorkspaceDialog = styled(Dialog, { name: 'WorkspaceDialog', slot: 'root' })(({ theme, variant }) => ({
+  '& .MuiDialogTitle-root': theme.unstable_sx({ typography: 'h2' }),
+  ...(variant === 'menu' && {
+    '& .MuiDialogContent-root': {
+      padding: 0,
+    },
+  }),
+}));
diff --git a/src/components/WorkspaceElastic.js b/src/components/WorkspaceElastic.js
index 01c2e79d2beba8f64d1d76b0607a3a2d69569a5f..f871ab9983bac48fd8445862cfda64de337265b3 100644
--- a/src/components/WorkspaceElastic.js
+++ b/src/components/WorkspaceElastic.js
@@ -1,11 +1,29 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import { Rnd } from 'react-rnd';
 import ResizeObserver from 'react-resize-observer';
-import classNames from 'classnames';
 import WorkspaceElasticWindow from '../containers/WorkspaceElasticWindow';
 import ns from '../config/css-ns';
 
+const Root = styled('div', { name: 'WorkspaceElastic', slot: 'root' })({
+  height: '100%',
+  position: 'relative',
+  width: '100%',
+});
+
+const StyledRnd = styled(Rnd)({
+  boxSizing: 'border-box',
+  margin: 0,
+  position: 'absolute',
+  transitionDuration: '.7s',
+  // order matters
+  // eslint-disable-next-line sort-keys
+  '&.react-draggable-dragging': {
+    transitionDuration: 'unset',
+  },
+});
+
 /**
  * Represents a work area that contains any number of windows
  * @memberof Workspace
@@ -16,7 +34,6 @@ class WorkspaceElastic extends Component {
    */
   render() {
     const {
-      classes,
       workspace,
       elasticLayout,
       setWorkspaceViewportDimensions,
@@ -28,13 +45,13 @@ class WorkspaceElastic extends Component {
     const offsetY = workspace.height / 2;
 
     return (
-      <div style={{ height: '100%', position: 'relative', width: '100%' }}>
+      <Root>
         <ResizeObserver
           onReflow={() => {}}
           onResize={(rect) => { setWorkspaceViewportDimensions(rect); }}
         />
 
-        <Rnd
+        <StyledRnd
           size={{
             height: workspace.height,
             width: workspace.width,
@@ -56,7 +73,7 @@ class WorkspaceElastic extends Component {
             setWorkspaceViewportPosition({ x: -1 * d.x - offsetX, y: -1 * d.y - offsetY });
           }}
           cancel={`.${ns('window')}`}
-          className={classNames(classes.workspace, ns('workspace'))}
+          className={ns('workspace')}
           disableDragging={!workspace.draggingEnabled}
         >
           {
@@ -67,14 +84,13 @@ class WorkspaceElastic extends Component {
               />
             ))
           }
-        </Rnd>
-      </div>
+        </StyledRnd>
+      </Root>
     );
   }
 }
 
 WorkspaceElastic.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   elasticLayout: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
   setWorkspaceViewportDimensions: PropTypes.func.isRequired,
   setWorkspaceViewportPosition: PropTypes.func.isRequired,
diff --git a/src/components/WorkspaceElasticWindow.js b/src/components/WorkspaceElasticWindow.js
index 54224913c4c213bf3f2f8058f9f8e05e520b6113..dea8c87b6ad8318300aae46219ba30f763da09af 100644
--- a/src/components/WorkspaceElasticWindow.js
+++ b/src/components/WorkspaceElasticWindow.js
@@ -1,9 +1,14 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
 import { Rnd } from 'react-rnd';
 import Window from '../containers/Window';
 import ns from '../config/css-ns';
 
+const StyledRnd = styled(Rnd)(({ focused, theme }) => ({
+  zIndex: focused ? theme.zIndex.modal - 1 : 'auto',
+}));
+
 /**
  * Represents a work area that contains any number of windows
  * @memberof Workspace
@@ -27,7 +32,9 @@ class WorkspaceElasticWindow extends Component {
     const offsetY = workspace.height / 2;
 
     return (
-      <Rnd
+      <StyledRnd
+        focused={focused}
+        className={focused ? classes.focused : undefined}
         key={`${layout.windowId}-${workspace.id}`}
         size={{
           height: layout.height + companionWindowDimensions.height,
@@ -52,14 +59,11 @@ class WorkspaceElasticWindow extends Component {
         }}
         dragHandleClassName={ns('window-top-bar')}
         cancel={`.${ns('window-menu-btn')}`}
-        className={
-          focused ? classes.focused : null
-        }
       >
         <Window
           windowId={layout.windowId}
         />
-      </Rnd>
+      </StyledRnd>
     );
   }
 }
diff --git a/src/components/WorkspaceExport.js b/src/components/WorkspaceExport.js
index 6e2a1b18a6fe1740125174c21cfd96a907c83154..d6a7962bd3f262c099ad38869a0a1f859bf536ed 100644
--- a/src/components/WorkspaceExport.js
+++ b/src/components/WorkspaceExport.js
@@ -1,19 +1,19 @@
 import { Component } from 'react';
-import Button from '@material-ui/core/Button';
-import Dialog from '@material-ui/core/Dialog';
-import DialogActions from '@material-ui/core/DialogActions';
-import DialogTitle from '@material-ui/core/DialogTitle';
-import DialogContent from '@material-ui/core/DialogContent';
-import Typography from '@material-ui/core/Typography';
-import Snackbar from '@material-ui/core/Snackbar';
-import IconButton from '@material-ui/core/IconButton';
-import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
-import CloseIcon from '@material-ui/icons/Close';
-import Accordion from '@material-ui/core/Accordion';
-import AccordionSummary from '@material-ui/core/AccordionSummary';
-import AccordionDetails from '@material-ui/core/AccordionDetails';
+import Button from '@mui/material/Button';
+import DialogActions from '@mui/material/DialogActions';
+import DialogTitle from '@mui/material/DialogTitle';
+import DialogContent from '@mui/material/DialogContent';
+import Typography from '@mui/material/Typography';
+import Snackbar from '@mui/material/Snackbar';
+import IconButton from '@mui/material/IconButton';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import CloseIcon from '@mui/icons-material/Close';
+import Accordion from '@mui/material/Accordion';
+import AccordionSummary from '@mui/material/AccordionSummary';
+import AccordionDetails from '@mui/material/AccordionDetails';
 import PropTypes from 'prop-types';
 import { CopyToClipboard } from 'react-copy-to-clipboard';
+import { WorkspaceDialog } from './WorkspaceDialog';
 
 /**
  */
@@ -54,7 +54,7 @@ export class WorkspaceExport extends Component {
    */
   render() {
     const {
-      children, classes, container, open, t,
+      children, container, open, t,
     } = this.props;
     const { copied } = this.state;
 
@@ -79,7 +79,7 @@ export class WorkspaceExport extends Component {
     }
 
     return (
-      <Dialog
+      <WorkspaceDialog
         id="workspace-export"
         container={container}
         open={open}
@@ -88,19 +88,18 @@ export class WorkspaceExport extends Component {
         fullWidth
         maxWidth="sm"
       >
-        <DialogTitle id="form-dialog-title" disableTypography>
-          <Typography variant="h2">{t('downloadExport')}</Typography>
+        <DialogTitle id="form-dialog-title">
+          {t('downloadExport')}
         </DialogTitle>
 
         <DialogContent>
-          <Accordion elevation={0}>
+          <Accordion elevation={2}>
             <AccordionSummary
-              classes={{ root: classes.accordionTitle }}
               expandIcon={<ExpandMoreIcon />}
             >
               <Typography variant="h4">{t('viewWorkspaceConfiguration')}</Typography>
             </AccordionSummary>
-            <AccordionDetails>
+            <AccordionDetails sx={{ overflow: 'scroll' }}>
               {children}
               <pre>
                 {this.exportedState()}
@@ -118,14 +117,13 @@ export class WorkspaceExport extends Component {
             <Button variant="contained" color="primary">{t('copy')}</Button>
           </CopyToClipboard>
         </DialogActions>
-      </Dialog>
+      </WorkspaceDialog>
     );
   }
 }
 
 WorkspaceExport.propTypes = {
   children: PropTypes.node,
-  classes: PropTypes.objectOf(PropTypes.string),
   container: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   exportableState: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
   handleClose: PropTypes.func.isRequired,
@@ -135,7 +133,6 @@ WorkspaceExport.propTypes = {
 
 WorkspaceExport.defaultProps = {
   children: null,
-  classes: {},
   container: null,
   open: false,
   t: key => key,
diff --git a/src/components/WorkspaceImport.js b/src/components/WorkspaceImport.js
index b0f2c347274ce179f6ddb02e6e9982896e238bad..3a50c482871fa14b6be568a083e83edea289c799 100644
--- a/src/components/WorkspaceImport.js
+++ b/src/components/WorkspaceImport.js
@@ -1,13 +1,12 @@
 import { Component } from 'react';
-import Dialog from '@material-ui/core/Dialog';
-import DialogTitle from '@material-ui/core/DialogTitle';
+import DialogTitle from '@mui/material/DialogTitle';
 import PropTypes from 'prop-types';
 import {
   DialogActions,
   TextField,
-  Typography,
-} from '@material-ui/core';
-import Button from '@material-ui/core/Button';
+} from '@mui/material';
+import Button from '@mui/material/Button';
+import { WorkspaceDialog } from './WorkspaceDialog';
 import ScrollIndicatedDialogContent from '../containers/ScrollIndicatedDialogContent';
 
 /**
@@ -65,7 +64,7 @@ export class WorkspaceImport extends Component {
     } = this.props;
 
     return (
-      <Dialog
+      <WorkspaceDialog
         aria-labelledby="workspace-import-title"
         id="workspace-import"
         onClose={handleClose}
@@ -73,8 +72,8 @@ export class WorkspaceImport extends Component {
         fullWidth
         maxWidth="sm"
       >
-        <DialogTitle id="workspace-import-title" disableTypography>
-          <Typography variant="h2">{t('importWorkspace')}</Typography>
+        <DialogTitle id="workspace-import-title">
+          {t('importWorkspace')}
         </DialogTitle>
         <ScrollIndicatedDialogContent>
           <TextField
@@ -84,19 +83,23 @@ export class WorkspaceImport extends Component {
             onChange={this.handleChange}
             minRows={15}
             variant="filled"
-            inputProps={{ autoFocus: 'autofocus', className: classes.textInput }}
+            sx={{
+              '& .MuiInputBase-input': { fontFamily: 'monospace' },
+              width: '100%',
+            }}
+            inputProps={{ autoFocus: 'autofocus' }}
             helperText={t('importWorkspaceHint')}
           />
         </ScrollIndicatedDialogContent>
         <DialogActions>
-          <Button className={classes.cancelBtn} onClick={handleClose}>
+          <Button onClick={handleClose}>
             {t('cancel')}
           </Button>
           <Button color="primary" onClick={this.handleImportConfig} variant="contained">
             {t('import')}
           </Button>
         </DialogActions>
-      </Dialog>
+      </WorkspaceDialog>
     );
   }
 }
diff --git a/src/components/WorkspaceMenu.js b/src/components/WorkspaceMenu.js
index 65e01ba2ed6dca3fff716f0c250a32cb0e9ea8d4..c6e9a191a60a864ef82114775e7d57a413c3e394 100644
--- a/src/components/WorkspaceMenu.js
+++ b/src/components/WorkspaceMenu.js
@@ -1,7 +1,7 @@
 import { Component } from 'react';
-import Menu from '@material-ui/core/Menu';
-import MenuItem from '@material-ui/core/MenuItem';
-import Typography from '@material-ui/core/Typography';
+import Menu from '@mui/material/Menu';
+import MenuItem from '@mui/material/MenuItem';
+import Typography from '@mui/material/Typography';
 import PropTypes from 'prop-types';
 import LanguageSettings from '../containers/LanguageSettings';
 import { NestedMenu } from './NestedMenu';
@@ -71,8 +71,10 @@ export class WorkspaceMenu extends Component {
       t,
       showZoomControls,
       toggleZoomControls,
-      ...menuProps
+      ...rest
     } = this.props;
+    const menuProps = { ...rest };
+    delete menuProps.tReady;
 
     const {
       changeTheme,
diff --git a/src/components/WorkspaceMenuButton.js b/src/components/WorkspaceMenuButton.js
index 71d8db245f5f7eeb25313dd953e8230be9058d6b..1ff00786511d9794a21b77b5230d4682a110fbe5 100644
--- a/src/components/WorkspaceMenuButton.js
+++ b/src/components/WorkspaceMenuButton.js
@@ -1,7 +1,6 @@
 import { Component } from 'react';
-import SettingsIcon from '@material-ui/icons/SettingsSharp';
+import SettingsIcon from '@mui/icons-material/SettingsSharp';
 import PropTypes from 'prop-types';
-import classNames from 'classnames';
 import WorkspaceMenu from '../containers/WorkspaceMenu';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 
@@ -46,7 +45,7 @@ export class WorkspaceMenuButton extends Component {
    * @return
    */
   render() {
-    const { classes, t } = this.props;
+    const { t } = this.props;
     const { anchorEl, open } = this.state;
 
     return (
@@ -55,7 +54,7 @@ export class WorkspaceMenuButton extends Component {
           aria-haspopup="true"
           aria-label={t('workspaceMenu')}
           aria-owns={open ? 'workspace-menu' : undefined}
-          className={classNames(classes.ctrlBtn, (open ? classes.ctrlBtnSelected : null))}
+          selected={open}
           id="menuBtn"
           onClick={this.handleMenuClick}
         >
@@ -73,7 +72,6 @@ export class WorkspaceMenuButton extends Component {
 }
 
 WorkspaceMenuButton.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   t: PropTypes.func,
 };
 
diff --git a/src/components/WorkspaceMosaic.js b/src/components/WorkspaceMosaic.js
index aad63fe5014fa3d760b79f87000ee56a7bb87702..0ac4faa5725b56d46a6691b3f1ba2c853b1d2191 100644
--- a/src/components/WorkspaceMosaic.js
+++ b/src/components/WorkspaceMosaic.js
@@ -1,5 +1,7 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
+import GlobalStyles from '@mui/material/GlobalStyles';
 import { DndContext } from 'react-dnd';
 import {
   Mosaic, MosaicWindow, getLeaves, createBalancedTreeFromLeaves,
@@ -10,6 +12,22 @@ import classNames from 'classnames';
 import MosaicRenderPreview from '../containers/MosaicRenderPreview';
 import Window from '../containers/Window';
 import MosaicLayout from '../lib/MosaicLayout';
+import globalReactMosaicStyles from '../styles/react-mosaic-component';
+
+const StyledMosaic = styled(Mosaic)({
+  '& .mosaic-preview': {
+    boxShadow: 'none',
+  },
+  '& .mosaic-tile': {
+    boxShadow: '0 1px 3px 0 rgba(0, 0, 0, .2), 0 1px 1px 0 rgba(0, 0, 0, .2), 0 2px 1px -1px rgba(0, 0, 0, .2)',
+  },
+  '& .mosaic-window': {
+    boxShadow: 'none',
+  },
+  '& .mosaic-window-toolbar': {
+    display: 'none !important',
+  },
+});
 
 /**
  * Represents a work area that contains any number of windows
@@ -143,18 +161,21 @@ export class WorkspaceMosaic extends Component {
   /**
    */
   render() {
-    const { layout, classes } = this.props;
+    const { layout } = this.props;
     return (
       <DndContext.Consumer>
         {(ctx) => (
-          <Mosaic
-            dragAndDropManager={ctx.dragDropManager}
-            renderTile={this.tileRenderer}
-            initialValue={layout || this.determineWorkspaceLayout()}
-            onChange={this.mosaicChange}
-            className={classNames('mirador-mosaic', classes.root)}
-            zeroStateView={this.zeroStateView}
-          />
+          <>
+            <GlobalStyles styles={{ ...globalReactMosaicStyles }} />
+            <StyledMosaic
+              dragAndDropManager={ctx.dragDropManager}
+              renderTile={this.tileRenderer}
+              initialValue={layout || this.determineWorkspaceLayout()}
+              onChange={this.mosaicChange}
+              className={classNames('mirador-mosaic')}
+              zeroStateView={this.zeroStateView}
+            />
+          </>
         )}
       </DndContext.Consumer>
     );
@@ -162,7 +183,6 @@ export class WorkspaceMosaic extends Component {
 }
 
 WorkspaceMosaic.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   layout: PropTypes.oneOfType(
     [PropTypes.object, PropTypes.string],
   ), // eslint-disable-line react/forbid-prop-types
diff --git a/src/components/WorkspaceOptionsButton.js b/src/components/WorkspaceOptionsButton.js
index bfde64bfb78daff64e4517f63240ff5261c21cd3..ad549551f2fe45cc99475b120ed0f6f57c317274 100644
--- a/src/components/WorkspaceOptionsButton.js
+++ b/src/components/WorkspaceOptionsButton.js
@@ -1,7 +1,6 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import classNames from 'classnames';
-import MoreHorizontalIcon from '@material-ui/icons/MoreHorizSharp';
+import MoreHorizontalIcon from '@mui/icons-material/MoreHorizSharp';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 import WorkspaceOptionsMenu from '../containers/WorkspaceOptionsMenu';
 
@@ -46,21 +45,18 @@ export class WorkspaceOptionsButton extends Component {
    * Returns the rendered component
   */
   render() {
-    const { classes, t } = this.props;
+    const { t } = this.props;
     const { anchorEl, open } = this.state;
 
     return (
       <>
         <MiradorMenuButton
           aria-label={t('workspaceOptions')}
-          className={
-            classNames(classes.ctrlBtn, (open ? classes.ctrlBtnSelected : null))
-          }
           onClick={this.handleMenuClick}
+          selected={open}
         >
           <MoreHorizontalIcon />
         </MiradorMenuButton>
-
         <WorkspaceOptionsMenu
           anchorEl={anchorEl}
           handleClose={this.handleMenuClose}
@@ -72,6 +68,5 @@ export class WorkspaceOptionsButton extends Component {
 }
 
 WorkspaceOptionsButton.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   t: PropTypes.func.isRequired,
 };
diff --git a/src/components/WorkspaceOptionsMenu.js b/src/components/WorkspaceOptionsMenu.js
index 6da23860f7748820f2ab7b2dd08b0028877f17bb..75aac27a94e95a337614cd8126e09cd823524530 100644
--- a/src/components/WorkspaceOptionsMenu.js
+++ b/src/components/WorkspaceOptionsMenu.js
@@ -1,11 +1,11 @@
 import { Component } from 'react';
 import PropTypes from 'prop-types';
-import ImportIcon from '@material-ui/icons/Input';
-import SaveAltIcon from '@material-ui/icons/SaveAltSharp';
-import ListItemIcon from '@material-ui/core/ListItemIcon';
-import Menu from '@material-ui/core/Menu';
-import MenuItem from '@material-ui/core/MenuItem';
-import Typography from '@material-ui/core/Typography';
+import ImportIcon from '@mui/icons-material/Input';
+import SaveAltIcon from '@mui/icons-material/SaveAltSharp';
+import ListItemIcon from '@mui/material/ListItemIcon';
+import Menu from '@mui/material/Menu';
+import MenuItem from '@mui/material/MenuItem';
+import Typography from '@mui/material/Typography';
 import WorkspaceExport from '../containers/WorkspaceExport';
 import WorkspaceImport from '../containers/WorkspaceImport';
 import { PluginHook } from './PluginHook';
diff --git a/src/components/WorkspaceSelectionDialog.js b/src/components/WorkspaceSelectionDialog.js
index f1efbf48d942d886ce160885882dfb157478282b..e606ef872fe8974f1ceba61c6e5c3f53afdd7922 100644
--- a/src/components/WorkspaceSelectionDialog.js
+++ b/src/components/WorkspaceSelectionDialog.js
@@ -1,18 +1,23 @@
 import { Component } from 'react';
-import Dialog from '@material-ui/core/Dialog';
-import DialogTitle from '@material-ui/core/DialogTitle';
+import DialogTitle from '@mui/material/DialogTitle';
 import {
   Card,
   CardContent,
   MenuList,
   MenuItem,
   Typography,
-} from '@material-ui/core';
+} from '@mui/material';
 import PropTypes from 'prop-types';
+import { styled } from '@mui/material/styles';
+import { WorkspaceDialog } from './WorkspaceDialog';
 import WorkspaceTypeElasticIcon from './icons/WorkspaceTypeElasticIcon';
 import WorkspaceTypeMosaicIcon from './icons/WorkspaceTypeMosaicIcon';
 import ScrollIndicatedDialogContent from '../containers/ScrollIndicatedDialogContent';
 
+const StyledDetails = styled('div')(() => ({
+  display: 'flex',
+  flexDirection: 'column',
+}));
 /**
  */
 export class WorkspaceSelectionDialog extends Component {
@@ -42,80 +47,133 @@ export class WorkspaceSelectionDialog extends Component {
    */
   render() {
     const {
-      classes, container, handleClose, open, children, t, workspaceType,
+      container, handleClose, open, children, t, workspaceType,
     } = this.props;
     return (
-      <Dialog
+      <WorkspaceDialog
         aria-labelledby="workspace-selection-dialog-title"
         container={container}
         id="workspace-selection-dialog"
         onClose={handleClose}
         open={open}
       >
-        <DialogTitle id="workspace-selection-dialog-title" disableTypography>
-          <Typography variant="h2">{t('workspaceSelectionTitle')}</Typography>
+        <DialogTitle id="workspace-selection-dialog-title">
+          {t('workspaceSelectionTitle')}
         </DialogTitle>
         <ScrollIndicatedDialogContent>
           {children}
           <MenuList
-            classes={{ root: classes.list }}
+            sx={{
+              '&active': {
+                outline: 'none',
+              },
+              '&focus': {
+                outline: 'none',
+              },
+              outline: 'none',
+            }}
             selected={workspaceType}
             autoFocusItem
           >
             <MenuItem
-              className={classes.menuItem}
+              sx={{
+                height: 'auto',
+                overflow: 'auto',
+                whiteSpace: 'inherit',
+              }}
               onClick={() => this.handleWorkspaceTypeChange('elastic')}
               selected={workspaceType === 'elastic'}
               value="elastic"
             >
-              <Card className={classes.card}>
+              <Card sx={{
+                backgroundColor: 'transparent',
+                borderRadius: '0',
+                boxShadow: '0 0 transparent',
+                display: 'flex',
+              }}
+              >
                 <WorkspaceTypeElasticIcon
-                  className={classes.svgIcon}
+                  sx={{
+                    flexShrink: 0,
+                    height: '90px',
+                    width: '120px',
+                  }}
                   viewBox="0 0 120 90"
                 />
-                <div className={classes.details}>
+                <StyledDetails>
                   <CardContent
-                    classes={{ root: classes.root }}
-                    className={classes.content}
+                    sx={{
+                      '&.MuiCardContent-root': {
+                        '&:last-child': {
+                          paddingBottom: '12px',
+                        },
+                        paddingBottom: 0,
+                        paddingTop: 0,
+                        textAlign: 'left',
+                      },
+                      flex: '1 0 auto',
+                    }}
                   >
-                    <Typography className={classes.headline} component="p" variant="h3">{t('elastic')}</Typography>
+                    <Typography sx={{ paddingBottom: '6px' }} component="p" variant="h3">{t('elastic')}</Typography>
                     <Typography variant="body1">{t('elasticDescription')}</Typography>
                   </CardContent>
-                </div>
+                </StyledDetails>
               </Card>
             </MenuItem>
             <MenuItem
-              className={classes.menuItem}
+              sx={{
+                height: 'auto',
+                overflow: 'auto',
+                whiteSpace: 'inherit',
+              }}
               onClick={() => this.handleWorkspaceTypeChange('mosaic')}
               selected={workspaceType === 'mosaic'}
               value="mosaic"
             >
-              <Card className={classes.card}>
+              <Card sx={{
+                backgroundColor: 'transparent',
+                borderRadius: '0',
+                boxShadow: '0 0 transparent',
+                display: 'flex',
+              }}
+              >
                 <WorkspaceTypeMosaicIcon
-                  className={classes.svgIcon}
+                  sx={{
+                    flexShrink: 0,
+                    height: '90px',
+                    width: '120px',
+                  }}
                   viewBox="0 0 120 90"
                 />
-                <div className={classes.details}>
+                <StyledDetails>
                   <CardContent
-                    className={classes.content}
-                    classes={{ root: classes.root }}
+                    sx={{
+                      '&.MuiCardContent-root': {
+                        '&:last-child': {
+                          paddingBottom: '12px',
+                        },
+                        paddingBottom: 0,
+                        paddingTop: 0,
+                        textAlign: 'left',
+                      },
+                      flex: '1 0 auto',
+                    }}
                   >
-                    <Typography className={classes.headline} component="p" variant="h3">{t('mosaic')}</Typography>
+                    <Typography sx={{ paddingBottom: '6px' }} component="p" variant="h3">{t('mosaic')}</Typography>
                     <Typography variant="body1">{t('mosaicDescription')}</Typography>
                   </CardContent>
-                </div>
+                </StyledDetails>
               </Card>
             </MenuItem>
           </MenuList>
         </ScrollIndicatedDialogContent>
-      </Dialog>
+      </WorkspaceDialog>
     );
   }
 }
 
 WorkspaceSelectionDialog.propTypes = {
   children: PropTypes.node,
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
   container: PropTypes.object, // eslint-disable-line react/forbid-prop-types
   handleClose: PropTypes.func.isRequired,
   open: PropTypes.bool,
diff --git a/src/components/ZoomControls.js b/src/components/ZoomControls.js
index 133c9950a8d8facc4598ac95c74a034d4e1d1e7a..19dc0002291173fe8c4de3467cd11a91b4519b77 100644
--- a/src/components/ZoomControls.js
+++ b/src/components/ZoomControls.js
@@ -1,10 +1,17 @@
 import { Component } from 'react';
-import AddCircleIcon from '@material-ui/icons/AddCircleOutlineSharp';
-import RemoveCircleIcon from '@material-ui/icons/RemoveCircleOutlineSharp';
+import AddCircleIcon from '@mui/icons-material/AddCircleOutlineSharp';
+import RemoveCircleIcon from '@mui/icons-material/RemoveCircleOutlineSharp';
+import { styled } from '@mui/material/styles';
 import PropTypes from 'prop-types';
 import RestoreZoomIcon from './icons/RestoreZoomIcon';
 import MiradorMenuButton from '../containers/MiradorMenuButton';
 
+const StyledZoomControlsWrapper = styled('div')({
+  display: 'flex',
+  flexDirection: 'row',
+  justifyContent: 'center',
+});
+
 /**
  */
 export class ZoomControls extends Component {
@@ -46,17 +53,11 @@ export class ZoomControls extends Component {
    */
   render() {
     const {
-      displayDivider, showZoomControls, classes, t, zoomToWorld,
+      t, zoomToWorld,
     } = this.props;
 
-    if (!showZoomControls) {
-      return (
-        <>
-        </>
-      );
-    }
     return (
-      <div className={classes.zoom_controls}>
+      <StyledZoomControlsWrapper>
         <MiradorMenuButton aria-label={t('zoomIn')} onClick={this.handleZoomInClick}>
           <AddCircleIcon />
         </MiradorMenuButton>
@@ -66,16 +67,12 @@ export class ZoomControls extends Component {
         <MiradorMenuButton aria-label={t('zoomReset')} onClick={() => zoomToWorld(false)}>
           <RestoreZoomIcon />
         </MiradorMenuButton>
-        {displayDivider && <span className={classes.divider} />}
-      </div>
+      </StyledZoomControlsWrapper>
     );
   }
 }
 
 ZoomControls.propTypes = {
-  classes: PropTypes.objectOf(PropTypes.string).isRequired,
-  displayDivider: PropTypes.bool,
-  showZoomControls: PropTypes.bool,
   t: PropTypes.func,
   updateViewport: PropTypes.func,
   viewer: PropTypes.shape({
@@ -88,8 +85,6 @@ ZoomControls.propTypes = {
 };
 
 ZoomControls.defaultProps = {
-  displayDivider: true,
-  showZoomControls: false,
   t: key => key,
   updateViewport: () => {},
   viewer: {},
diff --git a/src/components/icons/BookViewIcon.js b/src/components/icons/BookViewIcon.js
index a6668b1f30dd3f2334232b6a78defa451bf7e982..d26b9fe3ccb9071786167e894586d2f44d406e24 100644
--- a/src/components/icons/BookViewIcon.js
+++ b/src/components/icons/BookViewIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * BookViewIcon ~
diff --git a/src/components/icons/CanvasIndexIcon.js b/src/components/icons/CanvasIndexIcon.js
index 8d5af98b10ffc6d5a8b644a75b88260ccf3ef5af..2bac4808d03e9a90c20f4dd4531c8a5aa99cfb90 100644
--- a/src/components/icons/CanvasIndexIcon.js
+++ b/src/components/icons/CanvasIndexIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * Render the canvas index svg
diff --git a/src/components/icons/GalleryViewIcon.js b/src/components/icons/GalleryViewIcon.js
index 9a410033404f1fb35a6260eae3892bb9f91f8d11..cccd9d2c711c176af48926783c844e35d6a35600 100644
--- a/src/components/icons/GalleryViewIcon.js
+++ b/src/components/icons/GalleryViewIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * GalleryViewIcon ~
diff --git a/src/components/icons/MiradorIcon.js b/src/components/icons/MiradorIcon.js
index 920256dd9bf3c856729973c4343eff41265b0d60..43301fe4cb9c8bdf808da08666d037a97db9ee0b 100644
--- a/src/components/icons/MiradorIcon.js
+++ b/src/components/icons/MiradorIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * ThumbnailNavigationRightIcon ~
diff --git a/src/components/icons/RestoreZoomIcon.js b/src/components/icons/RestoreZoomIcon.js
index 2005e6e89c5b61f851bcf398014e26581008eb7e..f1cf1e2d1e3eafc22b8eb6777115b7ea6ee0b898 100644
--- a/src/components/icons/RestoreZoomIcon.js
+++ b/src/components/icons/RestoreZoomIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * RestoreZoomIcon ~
diff --git a/src/components/icons/ThumbnailNavigationBottomIcon.js b/src/components/icons/ThumbnailNavigationBottomIcon.js
index 5c7080a787b68f4431e3f5b31b73d9996a859eb3..4ef2b95448cac052e7cd245fe94e6fcf4fcd7e36 100644
--- a/src/components/icons/ThumbnailNavigationBottomIcon.js
+++ b/src/components/icons/ThumbnailNavigationBottomIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * ThumbnailNavigationBottomIcon ~
diff --git a/src/components/icons/ThumbnailNavigationRightIcon.js b/src/components/icons/ThumbnailNavigationRightIcon.js
index 8f22b31d00ac81fffb763d4fc82e49c2eedc1ae6..6690b01d280f0e7b0362ca138f9cda8d4fbaa875 100644
--- a/src/components/icons/ThumbnailNavigationRightIcon.js
+++ b/src/components/icons/ThumbnailNavigationRightIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * ThumbnailNavigationRightIcon ~
diff --git a/src/components/icons/WindowMaxIcon.js b/src/components/icons/WindowMaxIcon.js
index 9590bbb180d5ac1bbb1b322dfadc7960604efb70..3de34b6bf5e3d9efffcf7eefe179c5b229157546 100644
--- a/src/components/icons/WindowMaxIcon.js
+++ b/src/components/icons/WindowMaxIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * WindowMaxIcon ~
diff --git a/src/components/icons/WindowMinIcon.js b/src/components/icons/WindowMinIcon.js
index 7a2ef3be9ca1ec7ffd926f0b5edad8f8b66b247c..3118b915f7e0fcd8f0a22fc1269e8bd9fa62f3ca 100644
--- a/src/components/icons/WindowMinIcon.js
+++ b/src/components/icons/WindowMinIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * WindowMinIcon ~
diff --git a/src/components/icons/WindowOptionsIcon.js b/src/components/icons/WindowOptionsIcon.js
index 3e365c29307ee2d02b5970e4a4253f84caa5f657..e87dd282539643d1c8049c9b2a44dd4ef37913c0 100644
--- a/src/components/icons/WindowOptionsIcon.js
+++ b/src/components/icons/WindowOptionsIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * WindowMinIcon ~
diff --git a/src/components/icons/WorkspaceTypeElasticIcon.js b/src/components/icons/WorkspaceTypeElasticIcon.js
index c817330897909d6a7daafa8fbb88d29074187a48..e1ee53918ad5afed6ff58cad42078605514b34e9 100644
--- a/src/components/icons/WorkspaceTypeElasticIcon.js
+++ b/src/components/icons/WorkspaceTypeElasticIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * ElasticWorkspaceIcon ~
diff --git a/src/components/icons/WorkspaceTypeMosaicIcon.js b/src/components/icons/WorkspaceTypeMosaicIcon.js
index 5cdb0c34a10bed5204c03410330c7439bf0894ee..c1724ee7e88ed1b7dbf86f150f5935dcd13cf648 100644
--- a/src/components/icons/WorkspaceTypeMosaicIcon.js
+++ b/src/components/icons/WorkspaceTypeMosaicIcon.js
@@ -1,4 +1,4 @@
-import SvgIcon from '@material-ui/core/SvgIcon';
+import SvgIcon from '@mui/material/SvgIcon';
 
 /**
  * WorkspaceTypeMosaicIcon ~
diff --git a/src/config/settings.js b/src/config/settings.js
index 5aa08c8f99e97afc8a1d755cbf2a2677def553f9..caaebe2e15e340a62508363a3947e9618805e314 100644
--- a/src/config/settings.js
+++ b/src/config/settings.js
@@ -12,7 +12,7 @@ export default {
   themes: {
     dark: {
       palette: {
-        type: 'dark',
+        mode: 'dark',
         primary: {
           main: '#4db6ac',
         },
@@ -28,13 +28,13 @@ export default {
     },
     light: {
       palette: {
-        type: 'light',
+        mode: 'light',
       }
     }
   },
   theme: { // Sets up a MaterialUI theme. See https://material-ui.com/customization/default-theme/
     palette: {
-      type: 'light',
+      mode: 'light',
       primary: {
         main: '#1967d2', // Controls the color of the Add button and current window indicator
       },
@@ -61,6 +61,7 @@ export default {
       },
       section_divider: 'rgba(0, 0, 0, 0.25)',
       annotations: {
+        chipBackground: '#e0e0e0',
         hidden: { globalAlpha: 0 },
         default: { strokeStyle: '#00BFFF', globalAlpha: 1 },
         hovered: { strokeStyle: '#BF00FF', globalAlpha: 1 },
@@ -167,51 +168,248 @@ export default {
       },
       useNextVariants: true // set so that console deprecation warning is removed
     },
-    overrides: {
-      MuiListSubheader: {
-        root: {
-          '&[role="presentation"]:focus': {
-            outline: 0,
+    components: {
+      MuiMenuItem: {
+        variants: [
+          {
+            props: { variant: 'multiline' },
+            style: { whiteSpace: 'normal' }
           },
-        },
+        ]
       },
-      MuiTooltip: { // Overridden from https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Tooltip/Tooltip.js#L40-L70
-        tooltipPlacementLeft: {
-          ['@media (min-width:600px)']: {
-            margin: 0,
+      CompanionWindow: {
+        styleOverrides: {
+          closeButton: {
+            order: 4,
           },
-        },
-        tooltipPlacementRight: {
-          ['@media (min-width:600px)']: {
-            margin: 0,
+          contents: {
+            overflowY: 'auto',
+            wordBreak: 'break-word',
           },
-        },
-        tooltipPlacementTop: {
-          ['@media (min-width:600px)']: {
-            margin: 0,
+          controls: ({ ownerState }) => ({
+            alignItems: 'center',
+            display: 'flex',
+            flexFlow: 'row wrap',
+            flexGrow: 1,
+            justifyContent: (ownerState?.position === 'bottom' || ownerState?.position === 'far-bottom') ? 'flex-end' : 'flex-start',
+            minHeight: 48,
+            order: 3
+          }),
+          positionButton: {
+            marginLeft: -16,
+            order: -100,
+            width: 24,
           },
+          resize: ({ ownerState }) => ({
+            display: 'flex',
+            flexDirection: 'column',
+            minHeight: 50,
+            minWidth: (ownerState?.position === 'left') ? 235 : 100,
+            position: 'relative',
+          }),
+          root: ({ ownerState }) => ({
+            boxShadow: 'none',
+            boxSizing: 'border-box',
+            display: 'flex',
+            flexDirection: 'column',
+            minHeight: 0,
+            ...(ownerState?.position === 'right' && {
+              borderLeft: '0.5px solid rgba(0, 0, 0, 0.125)'
+            }),
+            ...(ownerState?.position === 'left' && {
+              borderRight: '0.5px solid rgba(0, 0, 0, 0.125)'
+            }),
+            ...(ownerState?.position === 'bottom' && {
+              borderTop: '0.5px solid rgba(0, 0, 0, 0.125)'
+            }),
+          }),
+          title: ({ theme }) => ({
+            ...theme.typography.subtitle1,
+            alignSelf: 'center',
+            flexGrow: 1,
+            width: 160
+          }),
+          toolbar: ({ theme }) => ({
+            alignItems: 'flex-start',
+            backgroundColor: theme.palette.shades.light,
+            flexWrap: 'wrap',
+            justifyContent: 'space-between',
+            minHeight: 'max-content',
+            paddingInlineStart: '1rem',
+          }),
         },
-        tooltipPlacementBottom: {
-          ['@media (min-width:600px)']: {
-            margin: 0,
+      },
+      CompanionWindowSection: {
+        styleOverrides: {
+          root: {
+            borderBlockEnd: '.5px solid rgba(0, 0, 0, 0.25)'
           },
         },
       },
-      MuiTouchRipple: {
-        childPulsate: {
-          animation: 'none',
+      IIIFHtmlContent: {
+        styleOverrides: {
+          root: ({ theme }) => ({
+            '& a': {
+              color: theme.palette.primary.main,
+              textDecoration: 'underline',
+            },
+          }),
         },
-        rippleVisible: {
-          animation: 'none',
+      },
+      IIIFThumbnail: {
+        styleOverrides: {
+          root: ({ ownerState }) => ({
+            ...(ownerState?.variant === 'inside' && {
+              display: 'inline-block',
+              height: 'inherit',
+              position: 'relative',
+            }),
+          }),
+          label: ({ ownerState }) => ({
+            overflow: 'hidden',
+            textOverflow: 'ellipsis',
+            lineHeight: '1.5em',
+            wordBreak: 'break-word',
+            ...(ownerState?.variant === 'inside' && {
+              color: '#ffffff',
+              WebkitLineClamp: 1,
+              whiteSpace: 'nowrap',
+            }),
+            ...(ownerState?.variant === 'outside' && {
+              display: '-webkit-box',
+              maxHeight: '3em',
+              MozBoxOrient: 'vertical',
+              WebkitLineClamp: 2,
+            }),
+            ...(ownerState?.variant === 'inside' && {
+              background: 'linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 70%, rgba(0,0,0,0) 100%)',
+              bottom: '5px',
+              boxSizing: 'border-box',
+              left: '0px',
+              padding: '4px',
+              position: 'absolute',
+              width: '100%',
+            }),
+          }),
+          image: ({ ownerState }) => ({
+            ...(ownerState?.border && {
+              border: '1px solid rgba(0, 0, 0, 0.125)',
+            }),
+          })
+        }
+      },
+      ThemeIcon: {
+        styleOverrides: {
+          icon: ({ ownerState }) => ({
+            color: (ownerState?.value === 'dark' ? '#000000' : undefined)
+          }),
         },
       },
-    },
-    props: {
+      MuiAccordion: {
+        variants: [
+          {
+            props: { variant: 'compact' },
+            style: {
+              '& .MuiAccordionSummary-root': {
+                minHeight: 'unset',
+                padding: 0,
+              },
+              '& .MuiAccordionSummary-content': {
+                margin: 0,
+              },
+              '& .MuiAccordionDetails-root': {
+                padding: 0,
+              },
+            },
+          },
+        ],
+      },
+      MuiButton: {
+        styleOverrides: {
+          inlineText: {
+            lineHeight: '1.5em',
+            padding: 0,
+            textAlign: 'inherit',
+            textTransform: 'none',
+
+          },
+          inlineTextSecondary: ({ theme }) => ({
+            color: theme.palette.secondary.main,
+          }),
+        }
+      },
       MuiButtonBase: {
-        disableTouchRipple: true,
+        defaultProps: {
+          disableTouchRipple: true,
+        },
+      },
+      MuiDialog: {
+        variants: [
+          {
+            props: { variant: 'contained' },
+            style: {
+              position: 'absolute',
+              '& .MuiBackdrop-root': {
+                position: 'absolute'
+              }
+            },
+          }
+        ]
+      },
+      MuiFab: {
+        styleOverrides: {
+          root: {
+            transition: 'none',
+          }
+        },
       },
       MuiLink: {
-        underline: 'always'
+        defaultProps: {
+          underline: 'always'
+        },
+      },
+      MuiListSubheader: {
+        styleOverrides: {
+          root: {
+            '&[role="presentation"]:focus': {
+              outline: 0,
+            },
+          },
+        },
+      },
+      MuiTooltip: { // Overridden from https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Tooltip/Tooltip.js#L40-L70
+        styleOverrides: {
+          tooltipPlacementLeft: {
+            ['@media (min-width:600px)']: {
+              margin: '0 !important',
+            },
+          },
+          tooltipPlacementRight: {
+            ['@media (min-width:600px)']: {
+              margin: '0 !important',
+            },
+          },
+          tooltipPlacementTop: {
+            ['@media (min-width:600px)']: {
+              margin: '0 !important',
+            },
+          },
+          tooltipPlacementBottom: {
+            ['@media (min-width:600px)']: {
+              margin: '0 !important',
+            },
+          },
+        },
+      },
+      MuiTouchRipple: {
+        styleOverrides: {
+          childPulsate: {
+            animation: 'none',
+          },
+          rippleVisible: {
+            animation: 'none',
+          },
+        },
       },
     },
   },
diff --git a/src/containers/AppProviders.js b/src/containers/AppProviders.js
index 22e8a3a06d4381880ecb305bea240a6df748ac1b..1ad1c6784dde9f7e5b583f13b2e39851bc397f40 100644
--- a/src/containers/AppProviders.js
+++ b/src/containers/AppProviders.js
@@ -11,7 +11,6 @@ import { AppProviders } from '../components/AppProviders';
  */
 const mapStateToProps = state => (
   {
-    createGenerateClassNameOptions: getConfig(state).createGenerateClassNameOptions,
     language: getConfig(state).language,
     theme: getTheme(state),
     translations: getConfig(state).translations,
diff --git a/src/containers/AttributionPanel.js b/src/containers/AttributionPanel.js
index 8e0801444dd60e1786f4924b52bc0c3b3316fe7d..94ae930e0f78abee992b3e42f660b539f9a3696d 100644
--- a/src/containers/AttributionPanel.js
+++ b/src/containers/AttributionPanel.js
@@ -1,13 +1,12 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
-import { withPlugins } from '../extend/withPlugins';
 import {
   getManifestLogo,
   getRequiredStatement,
   getRights,
 } from '../state/selectors';
+import { withPlugins } from '../extend/withPlugins';
 import { AttributionPanel } from '../components/AttributionPanel';
 
 /**
@@ -21,29 +20,7 @@ const mapStateToProps = (state, { id, windowId }) => ({
   rights: getRights(state, { windowId }),
 });
 
-/**
- *
- * @param theme
- * @returns {label: {paddingLeft: number}}}
- */
-const styles = theme => ({
-  logo: {
-    maxWidth: '100%',
-  },
-  placeholder: {
-    backgroundColor: theme.palette.grey[300],
-  },
-  section: {
-    borderBottom: `.5px solid ${theme.palette.section_divider}`,
-    paddingBottom: theme.spacing(1),
-    paddingLeft: theme.spacing(2),
-    paddingRight: theme.spacing(1),
-    paddingTop: theme.spacing(2),
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps),
   withPlugins('AttributionPanel'),
diff --git a/src/containers/AudioViewer.js b/src/containers/AudioViewer.js
index e422c6d6b6e00458773de3c365080307590b9fd9..2bcd274096fcff1ff41ce76fd584853c964734ed 100644
--- a/src/containers/AudioViewer.js
+++ b/src/containers/AudioViewer.js
@@ -1,7 +1,6 @@
 import { connect } from 'react-redux';
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import { AudioViewer } from '../components/AudioViewer';
 import { getConfig, getVisibleCanvasAudioResources, getVisibleCanvasCaptions } from '../state/selectors';
@@ -15,21 +14,8 @@ const mapStateToProps = (state, { windowId }) => (
   }
 );
 
-/** */
-const styles = () => ({
-  audio: {
-    width: '100%',
-  },
-  container: {
-    alignItems: 'center',
-    display: 'flex',
-    width: '100%',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, null),
   withPlugins('AudioViewer'),
 );
diff --git a/src/containers/CanvasAnnotations.js b/src/containers/CanvasAnnotations.js
index 5bebeae7885399b8685ac82bab9462b38020add4..5d420e745df44d7853cea0faacdf14aea44c0606 100644
--- a/src/containers/CanvasAnnotations.js
+++ b/src/containers/CanvasAnnotations.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import {
@@ -49,35 +48,8 @@ const mapDispatchToProps = {
   selectAnnotation: actions.selectAnnotation,
 };
 
-/** For withStlyes */
-const styles = theme => ({
-  annotationListItem: {
-    '&$hovered': {
-      backgroundColor: theme.palette.action.hover,
-    },
-    '&:hover,&:focus': {
-      backgroundColor: theme.palette.action.hover,
-    },
-    borderBottom: `0.5px solid ${theme.palette.divider}`,
-    cursor: 'pointer',
-    whiteSpace: 'normal',
-  },
-  chip: {
-    backgroundColor: theme.palette.background.paper,
-    marginRight: theme.spacing(0.5),
-    marginTop: theme.spacing(1),
-  },
-  hovered: {},
-  sectionHeading: {
-    paddingLeft: theme.spacing(2),
-    paddingRight: theme.spacing(1),
-    paddingTop: theme.spacing(2),
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('CanvasAnnotations'),
 );
diff --git a/src/containers/CanvasLayers.js b/src/containers/CanvasLayers.js
index 87041bed9628dd6faf56f67ebe2711078f0e60b3..1b5baf2ffb1580d4fc5cf233bdec4e11bcb9b263 100644
--- a/src/containers/CanvasLayers.js
+++ b/src/containers/CanvasLayers.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import * as actions from '../state/actions';
 import {
   getCanvasLabel,
@@ -26,81 +25,8 @@ const mapDispatchToProps = {
   updateLayers: actions.updateLayers,
 };
 
-/** For withStlyes */
-const styles = theme => ({
-  dragging: {},
-  dragHandle: {
-    alignItems: 'center',
-    borderRight: `0.5px solid ${theme.palette.divider}`,
-    display: 'flex',
-    flex: 1,
-    flexDirection: 'row',
-    marginBottom: -1 * theme.spacing(2) + 0.5,
-    marginRight: theme.spacing(1),
-    marginTop: -1 * theme.spacing(2),
-    maxWidth: theme.spacing(3),
-    width: theme.spacing(3),
-  },
-  image: {
-    borderBottom: `1px solid ${theme.palette.divider}`,
-  },
-  label: {
-    paddingLeft: theme.spacing(1),
-  },
-  list: {
-    paddingTop: 0,
-  },
-  listItem: {
-    '& $dragHandle': {
-      '&:hover': {
-        backgroundColor: theme.palette.action.hover,
-      },
-      backgroundColor: theme.palette.shades?.light,
-    },
-    '&$dragging': {
-      '& $dragHandle, & $dragHandle:hover': {
-        backgroundColor: theme.palette.action.selected,
-      },
-      backgroundColor: theme.palette.action.hover,
-    },
-    alignItems: 'stretch',
-    borderBottom: `0.5px solid ${theme.palette.divider}`,
-    cursor: 'pointer',
-    paddingBottom: theme.spacing(2),
-    paddingRight: theme.spacing(1),
-    paddingTop: theme.spacing(2),
-  },
-  opacityIcon: {
-    marginRight: theme.spacing(0.5),
-  },
-  opacityInput: {
-    ...theme.typography.caption,
-    '&::-webkit-outer-spin-button,&::-webkit-inner-spin-button': {
-      '-webkit-appearance': 'none',
-      margin: 0,
-    },
-    '-moz-appearance': 'textfield',
-    textAlign: 'right',
-    width: '3ch',
-  },
-  sectionHeading: {
-    paddingLeft: theme.spacing(2),
-    paddingRight: theme.spacing(1),
-    paddingTop: theme.spacing(2),
-  },
-  slider: {
-    marginLeft: theme.spacing(2),
-    marginRight: theme.spacing(2),
-    maxWidth: 150,
-  },
-  thumbnail: {
-    minWidth: 50,
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
 );
 
diff --git a/src/containers/ChangeThemeDialog.js b/src/containers/ChangeThemeDialog.js
index ade8c4eeebe49ebeb76b720f099b1ec4be4863c6..a473f22f1b8346f7d7c7fee65d637eee463b79cb 100644
--- a/src/containers/ChangeThemeDialog.js
+++ b/src/containers/ChangeThemeDialog.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core';
 import { withTranslation } from 'react-i18next';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
@@ -26,31 +25,8 @@ const mapStateToProps = state => ({
   themeIds: getThemeIds(state),
 });
 
-/** */
-const styles = theme => ({
-  dark: {
-    color: '#000000',
-  },
-  dialogContent: {
-    padding: 0,
-  },
-  light: {
-    color: '#BDBDBD',
-  },
-  listitem: {
-    '&:focus': {
-      backgroundColor: theme.palette.action.focus,
-    },
-    '&:hover': {
-      backgroundColor: theme.palette.action.hover,
-    },
-    cursor: 'pointer',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('ChangeThemeDialog'),
 );
diff --git a/src/containers/CollapsibleSection.js b/src/containers/CollapsibleSection.js
index 3daa9258b1ae29be903287fca527ea8ba41a459d..9e32b49c242eff19469c3f98207e15b163544b80 100644
--- a/src/containers/CollapsibleSection.js
+++ b/src/containers/CollapsibleSection.js
@@ -1,24 +1,9 @@
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { CollapsibleSection } from '../components/CollapsibleSection';
 
-const styles = {
-  button: {
-    padding: 0,
-  },
-  container: {
-    display: 'flex',
-    justifyContent: 'space-between',
-  },
-  heading: {
-    cursor: 'pointer',
-  },
-};
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
 );
 
 export default enhance(CollapsibleSection);
diff --git a/src/containers/CollectionDialog.js b/src/containers/CollectionDialog.js
index 1920dee3cd50bdb1303849969f2887d823aca7bd..02297bccbcae46e1233f62c569e812bbad4790b1 100644
--- a/src/containers/CollectionDialog.js
+++ b/src/containers/CollectionDialog.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core';
 import { withTranslation } from 'react-i18next';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
@@ -48,44 +47,8 @@ const mapStateToProps = (state, { windowId }) => {
   };
 };
 
-/** */
-const styles = theme => ({
-  collectionFilter: {
-    padding: '16px',
-    paddingTop: 0,
-  },
-  collectionItem: {
-    whiteSpace: 'normal',
-  },
-  collectionMetadata: {
-    padding: '16px',
-  },
-  dark: {
-    color: '#000000',
-  },
-  dialog: {
-    position: 'absolute !important',
-  },
-  dialogContent: {
-    padding: theme.spacing(1),
-  },
-  light: {
-    color: theme.palette.grey[400],
-  },
-  listitem: {
-    '&:focus': {
-      backgroundColor: theme.palette.action.focus,
-    },
-    '&:hover': {
-      backgroundColor: theme.palette.action.hover,
-    },
-    cursor: 'pointer',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   withWorkspaceContext,
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('CollectionDialog'),
diff --git a/src/containers/CompanionArea.js b/src/containers/CompanionArea.js
index 8ff8b9cb628481f47bbb5728f4b15dec52c463fb..f403a90849fa55e4ae43f23f98385d885eb3c8bc 100644
--- a/src/containers/CompanionArea.js
+++ b/src/containers/CompanionArea.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core';
 import { withTranslation } from 'react-i18next';
 import { withPlugins } from '../extend/withPlugins';
 import {
@@ -21,43 +20,8 @@ const mapDispatchToProps = ({
   setCompanionAreaOpen: actions.setCompanionAreaOpen,
 });
 
-/** */
-const styles = theme => ({
-  horizontal: {
-    flexDirection: 'column',
-    width: '100%',
-  },
-  left: {
-    minWidth: 235,
-  },
-  root: {
-    display: 'flex',
-    minHeight: 0,
-    position: 'relative',
-    zIndex: theme.zIndex.appBar - 2,
-  },
-  toggle: {
-    backgroundColor: theme.palette.background.paper,
-    border: `1px solid ${theme.palette.shades?.dark}`,
-    borderRadius: 0,
-    height: '48px',
-    left: '100%',
-    marginTop: '1rem',
-    padding: 2,
-    position: 'absolute',
-    width: '23px',
-    zIndex: theme.zIndex.drawer,
-  },
-  toggleButton: {
-    marginBottom: 12,
-    marginTop: 12,
-    padding: 0,
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('CompanionArea'),
 );
diff --git a/src/containers/CompanionWindow.js b/src/containers/CompanionWindow.js
index 9def7a3c3c0e468c0f643c9a302b42655cacb6a3..64a1806440f48be886d013f8cb4878be2b1f409d 100644
--- a/src/containers/CompanionWindow.js
+++ b/src/containers/CompanionWindow.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withSize } from 'react-sizeme';
 import { withPlugins } from '../extend/withPlugins';
 import { withRef } from '../extend/withRef';
@@ -45,95 +44,9 @@ const mapDispatchToProps = (dispatch, { windowId, id }) => ({
   ),
 });
 
-/**
- *
- * @param theme
- * @returns {{closeButton: {top: number, position: string, right: number},
- * root: {overflowY: string, width: string}}}
- */
-const styles = theme => ({
-  closeButton: {
-    order: 4,
-  },
-  'companionWindow-bottom': {
-    borderTop: `0.5px solid ${theme.palette.divider}`,
-  },
-  'companionWindow-left': {
-    borderRight: `0.5px solid ${theme.palette.divider}`,
-  },
-  'companionWindow-right': {
-    borderLeft: `0.5px solid ${theme.palette.divider}`,
-  },
-  companionWindowHeader: {
-    flexWrap: 'wrap',
-  },
-  companionWindowTitleControls: {
-    flexGrow: 1,
-    order: 1000,
-  },
-  companionWindowTitleControlsBottom: {
-    order: 'unset',
-  },
-  content: {
-    overflowY: 'auto',
-    wordBreak: 'break-word',
-  },
-  horizontal: {
-  },
-  positionButton: {
-    marginLeft: -16,
-    order: -100,
-    width: 24,
-  },
-  rnd: {
-    display: 'flex',
-    flexDirection: 'column',
-    minHeight: 0,
-  },
-  root: {
-    boxShadow: 'none',
-    boxSizing: 'border-box',
-    display: 'flex',
-    flexDirection: 'column',
-    minHeight: 0,
-  },
-  small: {},
-  titleControls: {
-    alignItems: 'center',
-    display: 'flex',
-    flexFlow: 'row wrap',
-    minHeight: 48,
-    order: 3,
-  },
-  toolbar: {
-    '&$small': {
-      '& $closeButton': {
-        order: 'unset',
-      },
-      '& $titleControls': {
-        order: 'unset',
-      },
-    },
-    alignItems: 'flex-start',
-    background: theme.palette.shades?.light,
-    justifyContent: 'space-between',
-    minHeight: 'max-content',
-    paddingLeft: theme.spacing(2),
-  },
-  vertical: {
-  },
-  windowSideBarTitle: {
-    ...theme.typography.subtitle1,
-    alignSelf: 'center',
-    flexGrow: 1,
-    width: 160,
-  },
-});
-
 const enhance = compose(
   withRef(),
   withTranslation(),
-  withStyles(styles),
   withSize(),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('CompanionWindow'),
diff --git a/src/containers/CustomPanel.js b/src/containers/CustomPanel.js
index 493ad146335bc1e55955512e721ad1bd83244ed4..3f83547018ed6f2b604d0bdb4d506556662133b8 100644
--- a/src/containers/CustomPanel.js
+++ b/src/containers/CustomPanel.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { CustomPanel } from '../components/CustomPanel';
 
@@ -11,17 +10,8 @@ import { CustomPanel } from '../components/CustomPanel';
 const mapStateToProps = (state, { id, windowId }) => ({
 });
 
-/**
- *
- * @param theme
- * @returns {label: {paddingLeft: number}}}
- */
-const styles = theme => ({
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps),
   withPlugins('CustomPanel'),
 );
diff --git a/src/containers/ErrorContent.js b/src/containers/ErrorContent.js
index ce3089f9d0f01b14b4d642e5194e2cf517ecd9e0..85443562090cbcdbf4501e01a7d765d561c44ef8 100644
--- a/src/containers/ErrorContent.js
+++ b/src/containers/ErrorContent.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { ErrorContent } from '../components/ErrorContent';
 import {
@@ -23,29 +22,8 @@ const mapStateToProps = (state, { companionWindowId, windowId }) => ({
   showJsError: getConfig(state).window.showJsError,
 });
 
-/**
- * @param theme
- * @returns {{typographyBody: {flexGrow: number, fontSize: number|string},
- * windowTopBarStyle: {minHeight: number, paddingLeft: number, backgroundColor: string}}}
- */
-const styles = theme => ({
-  alert: {
-    backgroundColor: theme.palette.error.main,
-    color: '#fff',
-    fontWeight: theme.typography.fontWeightMedium,
-  },
-  details: {
-    '& pre': {
-      height: '100px',
-      overflowY: 'scroll',
-    },
-    flexDirection: 'column',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps),
   withPlugins('ErrorContent'),
 );
diff --git a/src/containers/GalleryView.js b/src/containers/GalleryView.js
index 6b916d755abb443155a84da0efcac4ccd453b082..9c54be5a4b3971d371f187fdafbb58490e461945 100644
--- a/src/containers/GalleryView.js
+++ b/src/containers/GalleryView.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { GalleryView } from '../components/GalleryView';
 import { getCanvases, getSequenceViewingDirection } from '../state/selectors';
@@ -17,24 +16,7 @@ const mapStateToProps = (state, { windowId }) => (
   }
 );
 
-/**
- * Styles to be passed to the withStyles HOC
- */
-const styles = theme => ({
-  galleryContainer: {
-    alignItems: 'flex-start',
-    display: 'flex',
-    flexDirection: 'row',
-    flexWrap: 'wrap',
-    overflowX: 'hidden',
-    overflowY: 'scroll',
-    padding: '50px 0 50px 20px',
-    width: '100%',
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   connect(mapStateToProps),
   withPlugins('GalleryView'),
   // further HOC go here
diff --git a/src/containers/GalleryViewThumbnail.js b/src/containers/GalleryViewThumbnail.js
index 66d6a94a625c7f12db73a32d8e8d6fa2f29e16ca..c0306777ce9d9aecd58dfa13b733764dc95c5b51 100644
--- a/src/containers/GalleryViewThumbnail.js
+++ b/src/containers/GalleryViewThumbnail.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import flatten from 'lodash/flatten';
-import { withStyles } from '@material-ui/core/styles';
 import * as actions from '../state/actions';
 import { GalleryViewThumbnail } from '../components/GalleryViewThumbnail';
 import {
@@ -12,62 +11,6 @@ import {
   getCompanionWindowsForContent,
 } from '../state/selectors';
 
-/**
- * Styles to be passed to the withStyles HOC
- */
-const styles = theme => ({
-  annotationIcon: {
-    height: '1rem',
-    width: '1rem',
-  },
-  annotationsChip: {
-    ...theme.typography.caption,
-  },
-  avatar: {
-    backgroundColor: 'transparent',
-  },
-  chips: {
-    opacity: 0.875,
-    position: 'absolute',
-    right: 0,
-    textAlign: 'right',
-    top: 0,
-  },
-  galleryViewItem: {
-    '&$hasAnnotations': {
-      border: `2px solid ${theme.palette.action.selected}`,
-    },
-    '&$selected,&$selected$hasAnnotations': {
-      border: `2px solid ${theme.palette.primary.main}`,
-    },
-    '&:focus': {
-      outline: 'none',
-    },
-    '&:hover': {
-      backgroundColor: theme.palette.action.hover,
-    },
-    border: '2px solid transparent',
-    cursor: 'pointer',
-    display: 'inline-block',
-    margin: `${theme.spacing(1)}px ${theme.spacing(0.5)}px`,
-    maxHeight: props => props.config.height + 45,
-    minWidth: '60px',
-    overflow: 'hidden',
-    padding: theme.spacing(0.5),
-    position: 'relative',
-    width: 'min-content',
-  },
-  hasAnnotations: {},
-  searchChip: {
-    ...theme.typography.caption,
-    '&$selected $avatar': {
-      backgroundColor: theme.palette.highlights?.primary,
-    },
-    marginTop: 2,
-  },
-  selected: {},
-});
-
 /** */
 const mapStateToProps = (state, { canvas, windowId }) => {
   const currentCanvas = getCurrentCanvas(state, { windowId });
@@ -115,7 +58,6 @@ const mapDispatchToProps = (dispatch, { canvas, id, windowId }) => ({
 
 const enhance = compose(
   connect(mapStateToProps, mapDispatchToProps),
-  withStyles(styles),
   // further HOC go here
 );
 
diff --git a/src/containers/IIIFThumbnail.js b/src/containers/IIIFThumbnail.js
index c596b508cd92fee25b69b5e09e198011182363e7..6631a8deb3d5e296210213072e71a68cc30439c4 100644
--- a/src/containers/IIIFThumbnail.js
+++ b/src/containers/IIIFThumbnail.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import {
   getConfig,
@@ -16,51 +15,7 @@ const mapStateToProps = (state) => ({
   thumbnailsConfig: getConfig(state).thumbnails,
 });
 
-/**
- * Styles for withStyles HOC
- */
-const styles = theme => ({
-  caption: {
-    lineHeight: '1.5em',
-    wordBreak: 'break-word',
-  },
-  image: {},
-  insideCaption: {
-    color: '#ffffff',
-    lineClamp: '1',
-    whiteSpace: 'nowrap',
-  },
-  insideLabel: {
-    background: 'linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 70%, rgba(0,0,0,0) 100%)',
-    bottom: '5px',
-    boxSizing: 'border-box',
-    left: '0px',
-    padding: '4px',
-    position: 'absolute',
-    width: '100%',
-  },
-  insideRoot: {
-    display: 'inline-block',
-    height: 'inherit',
-    position: 'relative',
-  },
-  label: {
-    overflow: 'hidden',
-    textOverflow: 'ellipsis',
-  },
-  outsideCaption: {
-    boxOrient: 'vertical',
-    display: '-webkit-box',
-    lineClamp: '2',
-    maxHeight: '3em',
-  },
-  outsideLabel: {},
-  outsideRoot: {},
-  root: {},
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps),
   withPlugins('IIIFThumbnail'),
diff --git a/src/containers/LayersPanel.js b/src/containers/LayersPanel.js
index 16a1a9b01b5cec0d1005c357debb1fd72dcf801d..2d7352f4eb2ce54a4927221a3e2aef820a258e23 100644
--- a/src/containers/LayersPanel.js
+++ b/src/containers/LayersPanel.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { LayersPanel } from '../components/LayersPanel';
 import {
@@ -15,17 +14,8 @@ const mapStateToProps = (state, { id, windowId }) => ({
   canvasIds: getVisibleCanvasIds(state, { windowId }),
 });
 
-/**
- *
- * @param theme
- * @returns {label: {paddingLeft: number}}}
- */
-const styles = theme => ({
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps),
   withPlugins('LayersPanel'),
 );
diff --git a/src/containers/LocalePicker.js b/src/containers/LocalePicker.js
index 509fef4e3648f8a7b4e4baaf5b0052e12dc76607..2edb53b784605e79a283efcb2a08838131297894 100644
--- a/src/containers/LocalePicker.js
+++ b/src/containers/LocalePicker.js
@@ -1,27 +1,9 @@
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { LocalePicker } from '../components/LocalePicker';
 
-/**
- *
- * @param theme
- * @returns {label: {paddingLeft: number}}}
- */
-const styles = theme => ({
-  select: {
-    '&:focus': {
-      backgroundColor: theme.palette.background.paper,
-    },
-  },
-  selectEmpty: {
-    backgroundColor: theme.palette.background.paper,
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
 );
 
 export default enhance(LocalePicker);
diff --git a/src/containers/ManifestForm.js b/src/containers/ManifestForm.js
index e64b68d68c74d31e07ae6c7c3627b761b83a22a7..02a32621445f22f08e4137054d6b2895bd0e69fb 100644
--- a/src/containers/ManifestForm.js
+++ b/src/containers/ManifestForm.js
@@ -1,7 +1,6 @@
 import { connect } from 'react-redux';
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import { ManifestForm } from '../components/ManifestForm';
@@ -12,24 +11,8 @@ import { ManifestForm } from '../components/ManifestForm';
  * @private
  */
 const mapDispatchToProps = { addResource: actions.addResource };
-/**
- *
- * @param theme
- */
-const styles = theme => ({
-  buttons: {
-    textAlign: 'right',
-    [theme.breakpoints.up('sm')]: {
-      textAlign: 'inherit',
-    },
-  },
-  input: {
-    ...theme.typography.body1,
-  },
-});
 
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(null, mapDispatchToProps),
   withPlugins('ManifestForm'),
diff --git a/src/containers/ManifestListItem.js b/src/containers/ManifestListItem.js
index 6553a9cfa24a9e74766a40e28b1d66b3c7d87a15..55f5c43e90be8bbb35d0a048eeaef46d74a7ae43 100644
--- a/src/containers/ManifestListItem.js
+++ b/src/containers/ManifestListItem.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import {
   getManifest,
@@ -50,56 +49,8 @@ const mapDispatchToProps = {
   fetchManifest: actions.fetchManifest,
 };
 
-/**
- *
- * @param theme
- * @returns {{root: {}, label: {textAlign: string, textTransform: string}}}
- */
-const styles = theme => ({
-  active: {},
-  buttonGrid: {
-  },
-  label: {
-    textAlign: 'left',
-    textTransform: 'initial',
-  },
-  logo: {
-    height: '2.5rem',
-    maxWidth: '100%',
-    objectFit: 'contain',
-    paddingRight: 8,
-  },
-  placeholder: {
-    backgroundColor: theme.palette.grey[300],
-  },
-  root: {
-    '&$active': {
-      borderLeft: `4px solid ${theme.palette.primary.main}`,
-    },
-    '&:hover,&:focus-within': {
-      '&$active': {
-        borderLeft: `4px solid ${theme.palette.primary.main}`,
-      },
-      backgroundColor: theme.palette.action.hover,
-      borderLeft: `4px solid ${theme.palette.action.hover}`,
-    },
-    borderLeft: '4px solid transparent',
-    paddingLeft: theme.spacing(2),
-    paddingRight: theme.spacing(2),
-    [theme.breakpoints.up('sm')]: {
-      paddingLeft: theme.spacing(3),
-      paddingRight: theme.spacing(3),
-    },
-  },
-  thumbnail: {
-    maxWidth: '100%',
-    objectFit: 'contain',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('ManifestListItem'),
 );
diff --git a/src/containers/ManifestListItemError.js b/src/containers/ManifestListItemError.js
index 001d98750b73b2916dded1f97fb205e82df2f433..40d9f5f14dd188eb03b0b691d6eae96cffee308f 100644
--- a/src/containers/ManifestListItemError.js
+++ b/src/containers/ManifestListItemError.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { fetchManifest, removeResource } from '../state/actions';
 import { ManifestListItemError } from '../components/ManifestListItemError';
@@ -12,26 +11,8 @@ const mapDispatchToProps = {
   onTryAgainClick: fetchManifest,
 };
 
-/**
- *
- * @param theme
- * @returns {{manifestIdText: {wordBreak: string},
- * errorIcon: {color: string, width: string, height: string}}}
- */
-const styles = theme => ({
-  errorIcon: {
-    color: theme.palette.error.main,
-    height: '2rem',
-    width: '2rem',
-  },
-  manifestIdText: {
-    wordBreak: 'break-all',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(null, mapDispatchToProps),
   withPlugins('ManifestListItemError'),
 );
diff --git a/src/containers/ManifestRelatedLinks.js b/src/containers/ManifestRelatedLinks.js
index 6bcc356778bf8d8f6388d25c2e2698462ea1a119..a3f1edf9e0a702b8b94fe9f28b8e1317493a0cb3 100644
--- a/src/containers/ManifestRelatedLinks.js
+++ b/src/containers/ManifestRelatedLinks.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import {
   getManifestHomepage,
@@ -25,17 +24,7 @@ const mapStateToProps = (state, { id, windowId }) => ({
   seeAlso: getManifestSeeAlso(state, { windowId }),
 });
 
-const styles = {
-  labelValueMetadata: {
-    '& dd': {
-      marginBottom: '.5em',
-      marginLeft: '0',
-    },
-  },
-};
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps),
   withPlugins('ManifestRelatedLinks'),
diff --git a/src/containers/MinimalWindow.js b/src/containers/MinimalWindow.js
index 5ed8aec777d6abe9e2abaa2eedf6c55ecca01abf..d4e57cb75b41a5db524aaef50172dada9a6563d4 100644
--- a/src/containers/MinimalWindow.js
+++ b/src/containers/MinimalWindow.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import { MinimalWindow } from '../components/MinimalWindow';
@@ -22,42 +21,8 @@ const mapDispatchToProps = (dispatch, { windowId }) => ({
   removeWindow: () => dispatch(actions.removeWindow(windowId)),
 });
 
-/**
- * @param theme
- * @returns {{typographyBody: {flexGrow: number, fontSize: number|string},
- * windowTopBarStyle: {minHeight: number, paddingLeft: number, backgroundColor: string}}}
- */
-const styles = theme => ({
-  button: {
-    marginLeft: 'auto',
-  },
-  title: {
-    ...theme.typography.h6,
-    flexGrow: 1,
-    paddingLeft: theme.spacing(0.5),
-  },
-  window: {
-    backgroundColor: theme.palette.shades?.dark,
-    borderRadius: 0,
-    display: 'flex',
-    flexDirection: 'column',
-    height: '100%',
-    minHeight: 0,
-    overflow: 'hidden',
-    width: '100%',
-  },
-  windowTopBarStyle: {
-    backgroundColor: theme.palette.shades?.main,
-    borderTop: '2px solid transparent',
-    minHeight: 32,
-    paddingLeft: theme.spacing(0.5),
-    paddingRight: theme.spacing(0.5),
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('MinimalWindow'),
 );
diff --git a/src/containers/MosaicRenderPreview.js b/src/containers/MosaicRenderPreview.js
index 0103bab9c5beeba6658c2573ade4196ef5f2243b..149861f89f6eabdde49a83dd85592a80228a62e2 100644
--- a/src/containers/MosaicRenderPreview.js
+++ b/src/containers/MosaicRenderPreview.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core/styles';
 import { withTranslation } from 'react-i18next';
 import { withPlugins } from '../extend/withPlugins';
 import { getManifestTitle } from '../state/selectors';
@@ -13,18 +12,7 @@ const mapStateToProps = (state, { windowId }) => (
   }
 );
 
-/**
- *
- * @param theme
- */
-const styles = theme => ({
-  preview: {
-    ...theme.typography.h4,
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, null),
   withPlugins('MosaicRenderPreview'),
diff --git a/src/containers/OpenSeadragonViewer.js b/src/containers/OpenSeadragonViewer.js
index b5c59dff19b3cccda6d45e2430ffcf60487d4e80..adc01cf90c054e3d7eb0a28f26158bef22b89f5e 100644
--- a/src/containers/OpenSeadragonViewer.js
+++ b/src/containers/OpenSeadragonViewer.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import flatten from 'lodash/flatten';
 import { withPlugins } from '../extend/withPlugins';
 import { OpenSeadragonViewer } from '../components/OpenSeadragonViewer';
@@ -55,16 +54,7 @@ const mapDispatchToProps = {
   updateViewport: actions.updateViewport,
 };
 
-const styles = {
-  osdContainer: {
-    cursor: 'grab',
-    flex: 1,
-    position: 'relative',
-  },
-};
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('OpenSeadragonViewer'),
diff --git a/src/containers/PrimaryWindow.js b/src/containers/PrimaryWindow.js
index 336894235f31a71867a2e77da22347d9099c7909..1895e8053964c70d57bdb34f8316dc7704832f63 100644
--- a/src/containers/PrimaryWindow.js
+++ b/src/containers/PrimaryWindow.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import {
   getManifestoInstance, getVisibleCanvasAudioResources, getVisibleCanvasVideoResources, getWindow,
@@ -18,16 +17,7 @@ const mapStateToProps = (state, { windowId }) => {
   };
 };
 
-const styles = {
-  primaryWindow: {
-    display: 'flex',
-    flex: 1,
-    position: 'relative',
-  },
-};
-
 const enhance = compose(
-  withStyles(styles),
   connect(mapStateToProps, null),
   withPlugins('PrimaryWindow'),
 );
diff --git a/src/containers/SanitizedHtml.js b/src/containers/SanitizedHtml.js
index 932bfa0c0a650823e8c4d473d230fd749581b251..b6771d0d9e5585f2d35e7fd2ef7b7caaf468e334 100644
--- a/src/containers/SanitizedHtml.js
+++ b/src/containers/SanitizedHtml.js
@@ -1,16 +1,3 @@
-import { withStyles } from '@material-ui/core/styles';
 import { SanitizedHtml } from '../components/SanitizedHtml';
 
-/**
- * Styles for withStyles HOC
- */
-const styles = theme => ({
-  root: {
-    '& a': {
-      color: theme.palette.primary.main,
-      textDecoration: 'underline',
-    },
-  },
-});
-
-export default withStyles(styles)(SanitizedHtml);
+export default SanitizedHtml;
diff --git a/src/containers/ScrollIndicatedDialogContent.js b/src/containers/ScrollIndicatedDialogContent.js
index 66ec29e1abc18cec67c6603ae5dbc848bec301fe..aad0df3d57d586b115f3664b4001dfe7f58ed383 100644
--- a/src/containers/ScrollIndicatedDialogContent.js
+++ b/src/containers/ScrollIndicatedDialogContent.js
@@ -1,29 +1,3 @@
-import { withStyles } from '@material-ui/core/styles';
 import { ScrollIndicatedDialogContent } from '../components/ScrollIndicatedDialogContent';
 
-/**
- * Styles for the withStyles HOC
- */
-const styles = theme => ({
-  shadowScrollDialog: {
-    /* Shadow covers */
-    background: `linear-gradient(${theme.palette.background.paper} 30%, rgba(255, 255, 255, 0)), `
-                + `linear-gradient(rgba(255, 255, 255, 0), ${theme.palette.background.paper} 70%) 0 100%, `
-                // Shaddows
-                + 'radial-gradient(50% 0, farthest-side, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)), '
-                + 'radial-gradient(50% 100%, farthest-side, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) 0 100%,',
-    /* Shadow covers */
-    background: `linear-gradient(${theme.palette.background.paper} 30%, rgba(255, 255, 255, 0)), ` // eslint-disable-line no-dupe-keys
-                + `linear-gradient(rgba(255, 255, 255, 0), ${theme.palette.background.paper} 70%) 0 100%, `
-                // Shaddows
-                + 'radial-gradient(farthest-side at 50% 0, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)), '
-                + 'radial-gradient(farthest-side at 50% 100%, rgba(0, 0, 0, .2), rgba(0, 0, 0, 0)) 0 100%;',
-
-    backgroundAttachment: 'local, local, scroll, scroll',
-    backgroundRepeat: 'no-repeat',
-    backgroundSize: '100% 40px, 100% 40px, 100% 14px, 100% 14px',
-    overflowY: 'auto',
-  },
-});
-
-export default withStyles(styles)(ScrollIndicatedDialogContent);
+export default ScrollIndicatedDialogContent;
diff --git a/src/containers/SearchHit.js b/src/containers/SearchHit.js
index 009f44903e6e8f5f058248b27f98b1d9460911e1..7e67df152f62bde81582c712da441141f1590ecf 100644
--- a/src/containers/SearchHit.js
+++ b/src/containers/SearchHit.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { SearchHit } from '../components/SearchHit';
 import * as actions from '../state/actions';
@@ -70,60 +69,8 @@ const mapDispatchToProps = (dispatch, { windowId }) => ({
   ),
 });
 
-/** */
-const styles = theme => ({
-  adjacent: {},
-  focused: {},
-  hitCounter: {
-    ...theme.typography.subtitle2,
-    backgroundColor: theme.palette.hitCounter?.default,
-    height: 30,
-    marginRight: theme.spacing(1),
-    verticalAlign: 'inherit',
-  },
-  inlineButton: {
-    '& span': {
-      lineHeight: '1.5em',
-    },
-    margin: 0,
-    padding: 0,
-    textTransform: 'none',
-  },
-  listItem: {
-    '&$adjacent': {
-      '& $hitCounter': {
-        backgroundColor: theme.palette.highlights?.secondary,
-      },
-      '&$windowSelected': {
-        '& $hitCounter': {
-          backgroundColor: theme.palette.highlights?.primary,
-        },
-      },
-    },
-    '&$windowSelected': {
-      '& $hitCounter': {
-        backgroundColor: theme.palette.highlights?.primary,
-      },
-      '&$focused': {
-        '&:hover': {
-          backgroundColor: 'inherit',
-        },
-        backgroundColor: 'inherit',
-      },
-    },
-    borderBottom: `0.5px solid ${theme.palette.divider}`,
-    paddingRight: 8,
-  },
-  selected: {},
-  subtitle: {
-    marginBottom: theme.spacing(1.5),
-  },
-  windowSelected: {},
-});
-
 const enhance = compose(
   connect(mapStateToProps, mapDispatchToProps),
-  withStyles(styles),
   withTranslation(),
   withPlugins('SearchHit'),
 );
diff --git a/src/containers/SearchPanel.js b/src/containers/SearchPanel.js
index 64461b48c8f2ae69f343890eeaeae1d9ce34e208..5a5f4aa4088eb554c56345381e82ec0d54583c2a 100644
--- a/src/containers/SearchPanel.js
+++ b/src/containers/SearchPanel.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import * as actions from '../state/actions';
 import { withPlugins } from '../extend/withPlugins';
 import { SearchPanel } from '../components/SearchPanel';
@@ -22,27 +21,8 @@ const mapDispatchToProps = (dispatch, props) => ({
   removeSearch: () => dispatch(actions.removeSearch(props.windowId, props.id)),
 });
 
-/**
-* Styles for withStyles HOC
-*/
-const styles = theme => ({
-  clearChip: {
-    marginLeft: theme.spacing(1),
-  },
-  inlineButton: {
-    '& span': {
-      lineHeight: '1.5em',
-    },
-    margin: theme.spacing(2),
-    padding: 0,
-    textAlign: 'inherit',
-    textTransform: 'none',
-  },
-});
-
 const enhance = compose(
   connect(mapStateToProps, mapDispatchToProps),
-  withStyles(styles),
   withTranslation(),
   withPlugins('SearchPanel'),
 );
diff --git a/src/containers/SearchPanelControls.js b/src/containers/SearchPanelControls.js
index e81d46a4f3b48dedb66f93f4e2bc3034aeb77f12..e2f718ae07e613b059bc5d4ad2e206586be32b3c 100644
--- a/src/containers/SearchPanelControls.js
+++ b/src/containers/SearchPanelControls.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { SearchPanelControls } from '../components/SearchPanelControls';
 import * as actions from '../state/actions';
@@ -33,26 +32,8 @@ const mapDispatchToProps = {
   fetchSearch: actions.fetchSearch,
 };
 
-/** */
-const styles = theme => ({
-  endAdornment: {
-    position: 'absolute',
-    right: 0,
-  },
-  form: {
-    paddingBottom: theme.spacing(1),
-    paddingRight: theme.spacing(1.5),
-    width: '100%',
-  },
-  searchProgress: {
-    position: 'absolute',
-    right: 0,
-  },
-});
-
 const enhance = compose(
   connect(mapStateToProps, mapDispatchToProps),
-  withStyles(styles),
   withTranslation(),
   withPlugins('SearchPanelControls'),
 );
diff --git a/src/containers/SearchPanelNavigation.js b/src/containers/SearchPanelNavigation.js
index 614b2419209114973c256fc4029944724185b715..83b421ac3bcca2e24ca0e593390ecfca4eb56869 100644
--- a/src/containers/SearchPanelNavigation.js
+++ b/src/containers/SearchPanelNavigation.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { SearchPanelNavigation } from '../components/SearchPanelNavigation';
 import * as actions from '../state/actions';
@@ -37,17 +36,8 @@ const mapDispatchToProps = (dispatch, { windowId }) => ({
   ),
 });
 
-/** */
-const styles = theme => ({
-  body2: {
-    marginLeft: '-16px',
-    width: '100%',
-  },
-});
-
 const enhance = compose(
   connect(mapStateToProps, mapDispatchToProps),
-  withStyles(styles),
   withTranslation(),
   withPlugins('SearchPanelNavigation'),
 );
diff --git a/src/containers/SearchResults.js b/src/containers/SearchResults.js
index 15e660d99a297bfdb9a13a57d4f19e48697c8097..0684e36b8ef5ea04d37945200b31e4484639c9fe 100644
--- a/src/containers/SearchResults.js
+++ b/src/containers/SearchResults.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { SearchResults } from '../components/SearchResults';
 import * as actions from '../state/actions';
@@ -33,26 +32,8 @@ const mapDispatchToProps = {
   fetchSearch: actions.fetchSearch,
 };
 
-/** */
-const styles = theme => ({
-  moreButton: {
-    width: '100%',
-  },
-  navigation: {
-    textTransform: 'none',
-  },
-  noResults: {
-    ...theme.typography.h6,
-    padding: theme.spacing(2),
-  },
-  toggleFocus: {
-    ...theme.typography.subtitle1,
-  },
-});
-
 const enhance = compose(
   connect(mapStateToProps, mapDispatchToProps),
-  withStyles(styles),
   withTranslation(),
   withPlugins('SearchResults'),
 );
diff --git a/src/containers/SelectCollection.js b/src/containers/SelectCollection.js
index 446c32711f233e68c9ca4fe904e643c4e71d0ab2..e711f53708a42c3f8c395178f2c0dbca35b88e8a 100644
--- a/src/containers/SelectCollection.js
+++ b/src/containers/SelectCollection.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import * as actions from '../state/actions';
 import { withPlugins } from '../extend/withPlugins';
 import {
@@ -22,13 +21,9 @@ const mapStateToProps = (state, { windowId }) => {
 const mapDispatchToProps = {
   showCollectionDialog: actions.showCollectionDialog,
 };
-/** */
-const styles = (theme) => ({
-});
 
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('SelectCollection'),
 );
diff --git a/src/containers/SidebarIndexItem.js b/src/containers/SidebarIndexItem.js
index e58afff81c4fdd32cd41d211f51aff84590fed28..bc8a19001ea4d2ac41e743ecb4f338d9873506f7 100644
--- a/src/containers/SidebarIndexItem.js
+++ b/src/containers/SidebarIndexItem.js
@@ -1,21 +1,10 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { SidebarIndexItem } from '../components/SidebarIndexItem';
 
-/**
- * Styles for withStyles HOC
- */
-const styles = theme => ({
-  label: {
-    paddingLeft: theme.spacing(1),
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(null, null),
   withPlugins('SidebarIndexItem'),
diff --git a/src/containers/SidebarIndexList.js b/src/containers/SidebarIndexList.js
index 866e7d61d7229e239182378c8cd3e075a5a85cfa..de46a8893914f51188a78541e0899a866524b0f5 100644
--- a/src/containers/SidebarIndexList.js
+++ b/src/containers/SidebarIndexList.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import {
@@ -29,21 +28,7 @@ const mapDispatchToProps = (dispatch, { id, windowId }) => ({
   setCanvas: (...args) => dispatch(actions.setCanvas(...args)),
 });
 
-/**
- * Styles for withStyles HOC
- */
-const styles = theme => ({
-  label: {
-    paddingLeft: theme.spacing(1),
-  },
-  listItem: {
-    borderBottom: `0.5px solid ${theme.palette.divider}`,
-    paddingRight: theme.spacing(1),
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('SidebarIndexList'),
diff --git a/src/containers/SidebarIndexTableOfContents.js b/src/containers/SidebarIndexTableOfContents.js
index a626981f346b31775b7511a3c85d4065c0874c27..870f0c4087c0b5e0ae1ba55e59b5e048a3cc58cc 100644
--- a/src/containers/SidebarIndexTableOfContents.js
+++ b/src/containers/SidebarIndexTableOfContents.js
@@ -1,8 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
-import { alpha } from '@material-ui/core/styles/colorManipulator';
 import { withPlugins } from '../extend/withPlugins';
 import { SidebarIndexTableOfContents } from '../components/SidebarIndexTableOfContents';
 import {
@@ -34,45 +32,7 @@ const mapDispatchToProps = (dispatch, { id, windowId }) => ({
   toggleNode: nodeId => dispatch(actions.toggleNode(windowId, id, nodeId)),
 });
 
-/**
- * Styles for withStyles HOC
- */
-const styles = theme => ({
-  content: {
-    alignItems: 'flex-start',
-    borderLeft: '1px solid transparent',
-    padding: '8px 16px 8px 0',
-    width: 'auto',
-  },
-  group: {
-    borderLeft: `1px solid ${theme.palette.grey[300]}`,
-  },
-  label: {
-    paddingLeft: 0,
-  }, // needed for pseudo $label class
-  root: {
-    flexGrow: 1,
-  },
-  selected: {}, // needed for pseudo $selected class
-  treeItemRoot: {
-    '&:focus > $content': {
-      backgroundColor: theme.palette.action.selected,
-    },
-    '&:hover > $content': {
-      backgroundColor: theme.palette.action.hover,
-    },
-    '&:hover >$content $label, &:focus > $content $label, &$selected > $content $label, &$selected > $content $label:hover, &$selected:focus > $content $label': {
-      backgroundColor: 'transparent',
-    },
-  },
-  visibleNode: {
-    backgroundColor: alpha(theme.palette.highlights?.primary || theme.palette.action.selected, 0.35),
-    display: 'inline',
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('SidebarIndexTableOfContents'),
diff --git a/src/containers/SidebarIndexThumbnail.js b/src/containers/SidebarIndexThumbnail.js
index 9f582dc4647693cfb9d78d574648bd4169f066d1..74c831814fefcc36ec6e69a06643bce378d7ec89 100644
--- a/src/containers/SidebarIndexThumbnail.js
+++ b/src/containers/SidebarIndexThumbnail.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { SidebarIndexThumbnail } from '../components/SidebarIndexThumbnail';
 import { getConfig } from '../state/selectors';
@@ -15,17 +14,7 @@ const mapStateToProps = (state, { data }) => ({
   ...(getConfig(state).canvasNavigation || {}),
 });
 
-/**
- * Styles for withStyles HOC
- */
-const styles = theme => ({
-  label: {
-    paddingLeft: theme.spacing(1),
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, null),
   withPlugins('SidebarIndexThumbnail'),
diff --git a/src/containers/ThumbnailCanvasGrouping.js b/src/containers/ThumbnailCanvasGrouping.js
index 0804cee2d51e20fbf78c28f64f4d73cef0b9aa93..548c941ba941931b77e7915ca1549a43269c5211 100644
--- a/src/containers/ThumbnailCanvasGrouping.js
+++ b/src/containers/ThumbnailCanvasGrouping.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import { getCurrentCanvas } from '../state/selectors';
@@ -25,33 +24,8 @@ const mapStateToProps = (state, { data }) => ({
   currentCanvasId: (getCurrentCanvas(state, { windowId: data.windowId }) || {}).id,
 });
 
-/**
- * Styles for withStyles HOC
- */
-const styles = theme => ({
-  canvas: {
-    '&$currentCanvas': {
-      outline: `2px solid ${theme.palette.primary.main}`,
-      outlineOffset: '3px',
-    },
-    '&:hover': {
-      outline: `9px solid ${theme.palette.action.hover}`,
-      outlineOffset: '-2px',
-    },
-    boxSizing: 'border-box',
-    color: theme.palette.common.white,
-    cursor: 'pointer',
-    display: 'inline-block',
-    outline: 0,
-    whiteSpace: 'nowrap',
-  },
-  currentCanvas: {
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('ThumbnailCanvasGrouping'),
 );
diff --git a/src/containers/ThumbnailNavigation.js b/src/containers/ThumbnailNavigation.js
index e3be9a8f3363f1068771976c0d71929445d9e771..bf7c3490aaa6db191facdaad429aa0c14c5087b4 100644
--- a/src/containers/ThumbnailNavigation.js
+++ b/src/containers/ThumbnailNavigation.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import { ThumbnailNavigation } from '../components/ThumbnailNavigation';
@@ -40,20 +39,7 @@ const mapDispatchToProps = (dispatch, { windowId }) => ({
   setPreviousCanvas: (...args) => dispatch(actions.setPreviousCanvas(windowId)),
 });
 
-/**
- * Styles for withStyles HOC
- */
-const styles = theme => ({
-  thumbNavigation: {
-    '&:focus': {
-      boxShadow: 0,
-      outline: 0,
-    },
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('ThumbnailNavigation'),
diff --git a/src/containers/VideoViewer.js b/src/containers/VideoViewer.js
index 70e8ebc0832ba985c42d185bb3ffc98e074b8993..3c868940a211a4b048006184fb0928f8416eab99 100644
--- a/src/containers/VideoViewer.js
+++ b/src/containers/VideoViewer.js
@@ -1,7 +1,6 @@
 import { connect } from 'react-redux';
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import { VideoViewer } from '../components/VideoViewer';
 import { getConfig, getVisibleCanvasCaptions, getVisibleCanvasVideoResources } from '../state/selectors';
@@ -15,22 +14,8 @@ const mapStateToProps = (state, { windowId }) => (
   }
 );
 
-/** */
-const styles = () => ({
-  container: {
-    alignItems: 'center',
-    display: 'flex',
-    width: '100%',
-  },
-  video: {
-    maxHeight: '100%',
-    width: '100%',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, null),
   withPlugins('VideoViewer'),
 );
diff --git a/src/containers/ViewerInfo.js b/src/containers/ViewerInfo.js
index 7e2714d9b7880b574dea33859bb272bd98445394..6757102f98ea7cf276f753ea852eb133e2938148 100644
--- a/src/containers/ViewerInfo.js
+++ b/src/containers/ViewerInfo.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { ViewerInfo } from '../components/ViewerInfo';
 import {
@@ -29,20 +28,7 @@ const mapStateToProps = (state, props) => {
   };
 };
 
-const styles = {
-  osdInfo: {
-    order: 2,
-    overflow: 'hidden',
-    paddingBottom: 3,
-    textOverflow: 'ellipsis',
-    unicodeBidi: 'plaintext',
-    whiteSpace: 'nowrap',
-    width: '100%',
-  },
-};
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, null),
   withPlugins('ViewerInfo'),
diff --git a/src/containers/ViewerNavigation.js b/src/containers/ViewerNavigation.js
index 38fb8d4602b0e24e8095486f1c13aa6edaac7a33..3f142de4315e01ad9ad214fc58e0bfdcfc58111f 100644
--- a/src/containers/ViewerNavigation.js
+++ b/src/containers/ViewerNavigation.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import {
@@ -28,14 +27,7 @@ const mapDispatchToProps = (dispatch, { windowId }) => ({
   setPreviousCanvas: (...args) => dispatch(actions.setPreviousCanvas(windowId)),
 });
 
-const styles = {
-  osdNavigation: {
-    order: 1,
-  },
-};
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('ViewerNavigation'),
diff --git a/src/containers/Window.js b/src/containers/Window.js
index a06801e2a445d6a9530b9ec6de882fc994c79984..36cd4e14e1a5a87a6fd43cf8ec78a0f16e15c1f5 100644
--- a/src/containers/Window.js
+++ b/src/containers/Window.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core';
 import { withTranslation } from 'react-i18next';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
@@ -36,70 +35,8 @@ const mapDispatchToProps = (dispatch, { windowId }) => ({
   focusWindow: () => dispatch(actions.focusWindow(windowId)),
 });
 
-/**
- * @param theme
- */
-const styles = theme => ({
-  companionAreaBottom: {
-    display: 'flex',
-    flex: '0',
-    flexBasis: 'auto',
-    minHeight: 0,
-  },
-  companionAreaRight: {
-    display: 'flex',
-    flex: '0 1 auto',
-    minHeight: 0,
-  },
-  maximized: {},
-  middle: {
-    display: 'flex',
-    flex: '1',
-    flexDirection: 'row',
-    minHeight: 0,
-  },
-  middleLeft: {
-    display: 'flex',
-    flex: '1',
-    flexDirection: 'column',
-    minHeight: 0,
-  },
-  primaryWindow: {
-    display: 'flex',
-    flex: '1',
-    height: '300px',
-    minHeight: 0,
-    position: 'relative',
-  },
-  thumbnailArea: {
-    backgroundColor: theme.palette.shades?.dark,
-  },
-  thumbnailAreaBottom: {
-  },
-  thumbnailAreaRight: {
-    minWidth: 100,
-  },
-  window: {
-    '&$maximized': {
-      left: 0,
-      position: 'absolute',
-      top: 0,
-      zIndex: theme.zIndex.modal - 1,
-    },
-    backgroundColor: theme.palette.shades?.dark,
-    borderRadius: 0,
-    display: 'flex',
-    flexDirection: 'column',
-    height: '100%',
-    minHeight: 0,
-    overflow: 'hidden',
-    width: '100%',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('Window'),
 );
diff --git a/src/containers/WindowAuthenticationBar.js b/src/containers/WindowAuthenticationBar.js
index f3b7f8733367a8b7f2adf4c1e35f74d49b3353f1..b38a244aa80c6a2c31568c07caff1133affde8ab 100644
--- a/src/containers/WindowAuthenticationBar.js
+++ b/src/containers/WindowAuthenticationBar.js
@@ -1,62 +1,10 @@
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
-import { alpha } from '@material-ui/core/styles/colorManipulator';
 import { withPlugins } from '../extend/withPlugins';
 import { WindowAuthenticationBar } from '../components/WindowAuthenticationBar';
 
-/**
- * @param theme
- * @returns {{typographyBody: {flexGrow: number, fontSize: number|string},
- * windowTopBarStyle: {minHeight: number, paddingLeft: number, backgroundColor: string}}}
- */
-const styles = theme => ({
-  buttonInvert: {
-    '&:hover': {
-      backgroundColor: alpha(theme.palette.secondary.contrastText, 1 - theme.palette.action.hoverOpacity),
-    },
-    backgroundColor: theme.palette.secondary.contrastText,
-    marginLeft: theme.spacing(5),
-    paddingBottom: 0,
-    paddingTop: 0,
-  },
-  expanded: {
-    paddingLeft: theme.spacing(),
-    paddingRight: theme.spacing(),
-  },
-  failure: {
-    backgroundColor: theme.palette.error.dark,
-  },
-  fauxButton: {
-    marginLeft: theme.spacing(2.5),
-  },
-  icon: {
-    marginRight: theme.spacing(1.5),
-    verticalAlign: 'text-bottom',
-  },
-  label: {
-    lineHeight: 2.25,
-  },
-  paper: {
-    backgroundColor: theme.palette.secondary.main,
-    color: theme.palette.secondary.contrastText,
-    cursor: 'pointer',
-  },
-  topBar: {
-    '&:hover': {
-      backgroundColor: theme.palette.secondary.main,
-    },
-    alignItems: 'center',
-    display: 'flex',
-    justifyContent: 'inherit',
-    padding: theme.spacing(1),
-    textTransform: 'none',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   withPlugins('WindowAuthenticationBar'),
 );
 
diff --git a/src/containers/WindowCanvasNavigationControls.js b/src/containers/WindowCanvasNavigationControls.js
index f1f17053f8af45c4d492d70f51b93e49771e38d2..ca5088f34b6e32c34ef511435f01dd01143add70 100644
--- a/src/containers/WindowCanvasNavigationControls.js
+++ b/src/containers/WindowCanvasNavigationControls.js
@@ -1,45 +1,18 @@
 import { connect } from 'react-redux';
 import { compose } from 'redux';
 import { withSize } from 'react-sizeme';
-import { withStyles } from '@material-ui/core';
-import { alpha } from '@material-ui/core/styles/colorManipulator';
 import { withPlugins } from '../extend/withPlugins';
-import { getWorkspace } from '../state/selectors';
+import { getShowZoomControlsConfig, getWorkspace } from '../state/selectors';
 import { WindowCanvasNavigationControls } from '../components/WindowCanvasNavigationControls';
 
 /** */
 const mapStateToProps = (state, { windowId }) => ({
+  showZoomControls: getShowZoomControlsConfig(state),
   visible: getWorkspace(state).focusedWindowId === windowId,
 });
 
-/**
- *
- * @param theme
- */
-const styles = theme => ({
-  canvasNav: {
-    cursor: 'default',
-    display: 'flex',
-    flexDirection: 'row',
-    flexWrap: 'wrap',
-    justifyContent: 'center',
-    textAlign: 'center',
-  },
-  canvasNavStacked: {
-    flexDirection: 'column',
-  },
-  controls: {
-    backgroundColor: alpha(theme.palette.background.paper, 0.5),
-    bottom: 0,
-    position: 'absolute',
-    width: '100%',
-    zIndex: 50,
-  },
-});
-
 const enhance = compose(
   connect(mapStateToProps),
-  withStyles(styles),
   withSize(),
   withPlugins('WindowCanvasNavigationControls'),
 );
diff --git a/src/containers/WindowListButton.js b/src/containers/WindowListButton.js
index 74506d9dbaec7e421ae6288d6eb93e64210aeaec..68e984e497f7addbed5b701fcc07ec7499cae9bf 100644
--- a/src/containers/WindowListButton.js
+++ b/src/containers/WindowListButton.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { getWindowIds, getWorkspace } from '../state/selectors';
 import { WindowListButton } from '../components/WindowListButton';
@@ -12,26 +11,8 @@ const mapStateToProps = (state) => ({
   windowCount: getWindowIds(state).length,
 });
 
-/**
- *
- * @param theme
- * @returns {{background: {background: string}}}
- */
-const styles = theme => ({
-  badge: {
-    paddingLeft: 12,
-  },
-  ctrlBtn: {
-    margin: theme.spacing(1),
-  },
-  ctrlBtnSelected: {
-    backgroundColor: theme.palette.action.selected,
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, null),
   withPlugins('WindowListButton'),
 );
diff --git a/src/containers/WindowSideBar.js b/src/containers/WindowSideBar.js
index 012b2fd5d5cf273865948294150c6bb72c6d8043..022e34f310dbb64f9f64c5492c165314e84c7430 100644
--- a/src/containers/WindowSideBar.js
+++ b/src/containers/WindowSideBar.js
@@ -1,6 +1,5 @@
 import { connect } from 'react-redux';
 import { compose } from 'redux';
-import { withStyles } from '@material-ui/core';
 import { withTranslation } from 'react-i18next';
 import { withPlugins } from '../extend/withPlugins';
 import { WindowSideBar } from '../components/WindowSideBar';
@@ -19,32 +18,7 @@ const mapStateToProps = (state, { windowId }) => (
   }
 );
 
-/**
- *
- * @param theme
- * @returns {{toolbar: CSSProperties | toolbar | {minHeight}, grow: {flexGrow: number},
- * drawer: {overflowX: string, left: number, flexShrink: number, width: number, height: string}}}
- */
-const styles = theme => ({
-  drawer: {
-    flexShrink: 0,
-    height: '100%',
-    order: -1000,
-    zIndex: theme.zIndex.appBar - 1,
-  },
-  grow: {
-    flexGrow: 1,
-  },
-  paper: {
-    borderInlineEnd: `1px solid ${theme.palette.divider}`,
-    overflowX: 'hidden',
-    width: 48,
-  },
-  toolbar: theme.mixins.toolbar,
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, null),
   withPlugins('WindowSideBar'),
diff --git a/src/containers/WindowSideBarAnnotationsPanel.js b/src/containers/WindowSideBarAnnotationsPanel.js
index 904cea2f93053bcbca8d2c0903931f934ccc6e9d..8370a0c375692dbbf729443fe0607ebab4de0621 100644
--- a/src/containers/WindowSideBarAnnotationsPanel.js
+++ b/src/containers/WindowSideBarAnnotationsPanel.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import {
   getVisibleCanvasIds,
@@ -22,20 +21,8 @@ const mapStateToProps = (state, { windowId }) => ({
   canvasIds: getVisibleCanvasIds(state, { windowId }),
 });
 
-/** */
-const styles = theme => ({
-  section: {
-    borderBottom: `.5px solid ${theme.palette.section_divider}`,
-    paddingBottom: theme.spacing(1),
-    paddingLeft: theme.spacing(2),
-    paddingRight: theme.spacing(1),
-    paddingTop: theme.spacing(2),
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, null),
   withPlugins('WindowSideBarAnnotationsPanel'),
   // further HOC
diff --git a/src/containers/WindowSideBarButtons.js b/src/containers/WindowSideBarButtons.js
index 8449e9b6a28c6a0c2067618a8933da7fa888aa68..3b0511ae0fa9c694439f68416106ef173881b1d4 100644
--- a/src/containers/WindowSideBarButtons.js
+++ b/src/containers/WindowSideBarButtons.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core';
 import { withTranslation } from 'react-i18next';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
@@ -65,49 +64,8 @@ const mapStateToProps = (state, { windowId }) => ({
   sideBarPanel: ((getCompanionWindowsForPosition(state, { position: 'left', windowId }))[0] || {}).content,
 });
 
-/** */
-const style = theme => ({
-  badge: {
-    backgroundColor: theme.palette.notification?.main,
-  },
-  tab: {
-    '&:active': {
-      backgroundColor: theme.palette.action?.active,
-    },
-    '&:focus': {
-      '@media (hover: none)': {
-        backgroundColor: 'transparent',
-      },
-      backgroundColor: theme.palette.action?.hover,
-      textDecoration: 'none',
-      // Reset on touch devices, it doesn't add specificity
-    },
-    '&:hover': {
-      '@media (hover: none)': {
-        backgroundColor: 'transparent',
-      },
-      backgroundColor: theme.palette.action?.hover,
-      textDecoration: 'none',
-      // Reset on touch devices, it doesn't add specificity
-    },
-
-    borderRight: '2px solid transparent',
-    minWidth: 'auto',
-  },
-  tabSelected: {
-    borderRight: `2px solid ${theme.palette.primary?.main}`,
-  },
-  tabsFlexContainer: {
-    flexDirection: 'column',
-  },
-  tabsIndicator: {
-    display: 'none',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(style),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('WindowSideBarButtons'),
 );
diff --git a/src/containers/WindowSideBarCanvasPanel.js b/src/containers/WindowSideBarCanvasPanel.js
index 24324d253865b996f88b608e36c67245c11a0f36..e6b4befc734f459a96201631e3d1be18cb0b94cb 100644
--- a/src/containers/WindowSideBarCanvasPanel.js
+++ b/src/containers/WindowSideBarCanvasPanel.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import { WindowSideBarCanvasPanel } from '../components/WindowSideBarCanvasPanel';
@@ -53,37 +52,8 @@ const mapDispatchToProps = (dispatch, { id, windowId }) => ({
   ),
 });
 
-/**
- *
- * @param theme
- */
-const styles = theme => ({
-  break: {
-    flexBasis: '100%',
-    height: 0,
-  },
-  collectionNavigationButton: {
-    textTransform: 'none',
-  },
-  label: {
-    paddingLeft: theme.spacing(1),
-  },
-  select: {
-    '&:focus': {
-      backgroundColor: theme.palette.background.paper,
-    },
-  },
-  selectEmpty: {
-    backgroundColor: theme.palette.background.paper,
-  },
-  variantTab: {
-    minWidth: 'auto',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('WindowSideBarCanvasPanel'),
 );
diff --git a/src/containers/WindowSideBarCollectionPanel.js b/src/containers/WindowSideBarCollectionPanel.js
index 32b31a77b283f90756a568cffe44be7282f31d5b..738c11125a4d23e87226f674a85ee2423d71603c 100644
--- a/src/containers/WindowSideBarCollectionPanel.js
+++ b/src/containers/WindowSideBarCollectionPanel.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import {
@@ -56,22 +55,7 @@ const mapDispatchToProps = (dispatch, { id, windowId }) => ({
   updateWindow: (...args) => dispatch(actions.updateWindow(windowId, ...args)),
 });
 
-/**
- * Styles for withStyles HOC
- */
-const styles = theme => ({
-  label: {
-    paddingLeft: theme.spacing(1),
-  },
-  menuItem: {
-    borderBottom: `0.5px solid ${theme.palette.divider}`,
-    paddingRight: theme.spacing(1),
-    whiteSpace: 'normal',
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('WindowSideBarCollectionPanel'),
diff --git a/src/containers/WindowSideBarInfoPanel.js b/src/containers/WindowSideBarInfoPanel.js
index 9fc498ce117521c64e176a2559bebd8c8b40692d..19de86776b88a5277762ce3e4b8c74eb95cf9e86 100644
--- a/src/containers/WindowSideBarInfoPanel.js
+++ b/src/containers/WindowSideBarInfoPanel.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import {
@@ -33,24 +32,8 @@ const mapDispatchToProps = (dispatch, { windowId, id }) => ({
   setLocale: locale => dispatch(actions.updateCompanionWindow(windowId, id, { locale })),
 });
 
-/**
- *
- * @param theme
- * @returns {label: {paddingLeft: number}}}
- */
-const styles = theme => ({
-  section: {
-    borderBottom: `.5px solid ${theme.palette.section_divider}`,
-    paddingBottom: theme.spacing(1),
-    paddingLeft: theme.spacing(2),
-    paddingRight: theme.spacing(1),
-    paddingTop: theme.spacing(2),
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('WindowSideBarInfoPanel'),
 );
diff --git a/src/containers/WindowThumbnailSettings.js b/src/containers/WindowThumbnailSettings.js
index 24878457a780b19e3e280e0e289179636d0fb28b..d773247feef8d32d57fcaa1835dba73c3eb9dff3 100644
--- a/src/containers/WindowThumbnailSettings.js
+++ b/src/containers/WindowThumbnailSettings.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import { getThumbnailNavigationPosition, getThemeDirection } from '../state/selectors';
@@ -26,22 +25,7 @@ const mapStateToProps = (state, { windowId }) => (
   }
 );
 
-/** */
-const styles = theme => ({
-  label: {
-    borderBottom: '2px solid transparent',
-  },
-  MenuItem: {
-    display: 'inline-block',
-  },
-  selectedLabel: {
-    borderBottom: `2px solid ${theme.palette.secondary.main}`,
-    color: theme.palette.secondary.main,
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(null, { withRef: true }),
   connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true }),
   withPlugins('WindowThumbnailSettings'),
diff --git a/src/containers/WindowTopBar.js b/src/containers/WindowTopBar.js
index 27dd9b83248c59267293ebb9b86512ef3b8a13e1..ae9fc34b90eef656931403890f734f980993ac6b 100644
--- a/src/containers/WindowTopBar.js
+++ b/src/containers/WindowTopBar.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import { getWindowConfig, isFocused } from '../state/selectors';
@@ -35,31 +34,8 @@ const mapDispatchToProps = (dispatch, { windowId }) => ({
   toggleWindowSideBar: () => dispatch(actions.toggleWindowSideBar(windowId)),
 });
 
-/**
- * @param theme
- * @returns {{typographyBody: {flexGrow: number, fontSize: number|string},
- * windowTopBarStyle: {minHeight: number, paddingLeft: number, backgroundColor: string}}}
- */
-const styles = theme => ({
-  focused: {},
-  windowTopBarStyle: {
-    '&$focused': {
-      borderTop: `2px solid ${theme.palette.primary.main}`,
-    },
-    backgroundColor: theme.palette.shades?.main,
-    borderTop: '2px solid transparent',
-    minHeight: 32,
-    paddingLeft: theme.spacing(0.5),
-    paddingRight: theme.spacing(0.5),
-  },
-  windowTopBarStyleDraggable: {
-    cursor: 'move',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('WindowTopBar'),
 );
diff --git a/src/containers/WindowTopBarPluginArea.js b/src/containers/WindowTopBarPluginArea.js
index 4bcdc88f5ae95da56b721b52d856012ded348c0a..cf05b64af3e923718c58de9d28f952c2e8147d50 100644
--- a/src/containers/WindowTopBarPluginArea.js
+++ b/src/containers/WindowTopBarPluginArea.js
@@ -1,17 +1,11 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import { WindowTopBarPluginArea } from '../components/WindowTopBarPluginArea';
 
-/**
- */
-const styles = {};
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(null, null),
   withPlugins('WindowTopBarPluginArea'),
 );
diff --git a/src/containers/WindowTopBarPluginMenu.js b/src/containers/WindowTopBarPluginMenu.js
index 510d7a35de8418cb7c831e145e9d5178cc0092e2..4900528e9f5cd7ca363f978ced229ed8c46bff41 100644
--- a/src/containers/WindowTopBarPluginMenu.js
+++ b/src/containers/WindowTopBarPluginMenu.js
@@ -1,25 +1,12 @@
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import { WindowTopBarPluginMenu } from '../components/WindowTopBarPluginMenu';
 import { withWorkspaceContext } from '../contexts/WorkspaceContext';
 
-/**
- *
- * @param theme
- * @returns {{ctrlBtn: {margin: (number|string)}}}
- */
-const styles = theme => ({
-  ctrlBtnSelected: {
-    backgroundColor: theme.palette.action.selected,
-  },
-});
-
 const enhance = compose(
   withTranslation(),
   withWorkspaceContext,
-  withStyles(styles),
   withPlugins('WindowTopBarPluginMenu'),
 );
 
diff --git a/src/containers/WindowTopBarTitle.js b/src/containers/WindowTopBarTitle.js
index 5cb51b8274b7ffc7b1bca026c5b5fe5cfea0207f..fbdf31288be412e6bddec49981aa5a6a0a4838d3 100644
--- a/src/containers/WindowTopBarTitle.js
+++ b/src/containers/WindowTopBarTitle.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import { getManifestStatus, getManifestTitle, getWindowConfig } from '../state/selectors';
 import { WindowTopBarTitle } from '../components/WindowTopBarTitle';
@@ -14,20 +13,8 @@ const mapStateToProps = (state, { windowId }) => ({
   manifestTitle: getManifestTitle(state, { windowId }),
 });
 
-/**
- * @param theme
- */
-const styles = theme => ({
-  title: {
-    ...theme.typography.h6,
-    flexGrow: 1,
-    paddingLeft: theme.spacing(0.5),
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, null),
   withPlugins('WindowTopBarTitle'),
 );
diff --git a/src/containers/WindowTopMenuButton.js b/src/containers/WindowTopMenuButton.js
index 54d863e2b688ca032ac5ed7af9e093e176b7fc18..8a114a8dea2d3d6f7c2b455ab27f820b8f97653d 100644
--- a/src/containers/WindowTopMenuButton.js
+++ b/src/containers/WindowTopMenuButton.js
@@ -1,23 +1,10 @@
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import { WindowTopMenuButton } from '../components/WindowTopMenuButton';
 
-/**
- *
- * @param theme
- * @returns {{ctrlBtn: {margin: (number|string)}}}
- */
-const styles = theme => ({
-  ctrlBtnSelected: {
-    backgroundColor: theme.palette.action.selected,
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   withPlugins('WindowTopMenuButton'),
 );
 
diff --git a/src/containers/WindowViewSettings.js b/src/containers/WindowViewSettings.js
index 6fc417f284b1f5b585c85ec369ddbd31946ece8a..3e34e5949b1ede7323c50648a8699cd3f111dfe7 100644
--- a/src/containers/WindowViewSettings.js
+++ b/src/containers/WindowViewSettings.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import { getAllowedWindowViewTypes, getWindowViewType } from '../state/selectors';
@@ -26,22 +25,7 @@ const mapStateToProps = (state, { windowId }) => (
   }
 );
 
-/** */
-const styles = theme => ({
-  label: {
-    borderBottom: '2px solid transparent',
-  },
-  MenuItem: {
-    display: 'inline-block',
-  },
-  selectedLabel: {
-    borderBottom: `2px solid ${theme.palette.secondary.main}`,
-    color: theme.palette.secondary.main,
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(null, { withRef: true }),
   connect(mapStateToProps, mapDispatchToProps, null, { forwardRef: true }),
   withPlugins('WindowViewSettings'),
diff --git a/src/containers/Workspace.js b/src/containers/Workspace.js
index 6eac59013b39931e67ce89e965cb58bfa3678c7b..f9288e8d94c750a2e8bcafb881abbbea7779bf55 100644
--- a/src/containers/Workspace.js
+++ b/src/containers/Workspace.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { Workspace } from '../components/Workspace';
 import {
@@ -18,7 +17,6 @@ import * as actions from '../state/actions';
 const mapStateToProps = state => (
   {
     allowNewWindows: getConfig(state).workspace.allowNewWindows,
-    isWorkspaceControlPanelVisible: getConfig(state).workspaceControlPanel.enabled,
     maximizedWindowIds: getMaximizedWindowsIds(state),
     windowIds: getWindowIds(state),
     workspaceId: getWorkspace(state).id,
@@ -35,35 +33,8 @@ const mapDispatchToProps = {
   addWindow: actions.addWindow,
 };
 
-/**
- * @param theme
- */
-const styles = theme => ({
-  workspaceViewport: {
-    bottom: 0,
-    left: 0,
-    margin: 0,
-    overflow: 'hidden',
-    position: 'absolute',
-    right: 0,
-    top: 0,
-  },
-  workspaceWithControlPanel: {
-    paddingTop: 74,
-  },
-  // injection order matters here
-  // eslint-disable-next-line sort-keys
-  '@media (min-width: 600px)': {
-    workspaceWithControlPanel: {
-      paddingLeft: 68,
-      paddingTop: 0,
-    },
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('Workspace'),
   // further HOC go here
diff --git a/src/containers/WorkspaceAdd.js b/src/containers/WorkspaceAdd.js
index 25f8903234c26197b3b0746936db93a93ef8eda6..0c0883945d1b04b1e8ea07aa1e822f5486ac15b9 100644
--- a/src/containers/WorkspaceAdd.js
+++ b/src/containers/WorkspaceAdd.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import { WorkspaceAdd } from '../components/WorkspaceAdd';
@@ -24,73 +23,8 @@ const mapDispatchToProps = {
   setWorkspaceAddVisibility: actions.setWorkspaceAddVisibility,
 };
 
-/**
- *
- * @param theme
- * @returns {{typographyBody: {flexGrow: number, fontSize: string},
- * form: {paddingBottom: number, paddingTop: number, marginTop: number},
- * fab: {bottom: number, position: string, right: number},
- * menuButton: {marginRight: number, marginLeft: number}}}
- */
-const styles = theme => ({
-  displayNone: {
-    display: 'none',
-  },
-  fab: {
-    bottom: theme.spacing(2),
-    position: 'absolute',
-    right: theme.spacing(2),
-  },
-  form: {
-    left: '0',
-    marginTop: 48,
-    paddingBottom: theme.spacing(2),
-    paddingLeft: theme.spacing(2),
-    paddingRight: theme.spacing(2),
-    [theme.breakpoints.up('sm')]: {
-      paddingLeft: theme.spacing(3),
-      paddingRight: theme.spacing(3),
-    },
-    paddingTop: theme.spacing(2),
-    right: '0',
-  },
-  list: {
-    margin: '16px',
-  },
-  menuButton: {
-    marginLeft: -12,
-    marginRight: 20,
-  },
-  paper: {
-    borderTop: '0',
-    left: '0',
-    [theme.breakpoints.up('sm')]: {
-      left: '65px',
-    },
-  },
-  typographyBody: {
-    flexGrow: 1,
-  },
-  workspaceAdd: {
-    boxSizing: 'border-box',
-    height: '100%',
-    overflowX: 'hidden',
-    overflowY: 'auto',
-    paddingTop: 68,
-  },
-  // injection order matters
-  // eslint-disable-next-line sort-keys
-  '@media (min-width: 600px)': {
-    workspaceAdd: {
-      paddingLeft: 68,
-      paddingTop: 0,
-    },
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('WorkspaceAdd'),
 );
diff --git a/src/containers/WorkspaceAddButton.js b/src/containers/WorkspaceAddButton.js
index 427676b481fa75442a6f9ae9eba09eba199e7151..cec63fcb4a2e3b12701ff83936e7a44349af6e4f 100644
--- a/src/containers/WorkspaceAddButton.js
+++ b/src/containers/WorkspaceAddButton.js
@@ -1,13 +1,37 @@
 import { connect } from 'react-redux';
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
-import withWidth from '@material-ui/core/withWidth';
+import { useTheme } from '@mui/material/styles';
+import useMediaQuery from '@mui/material/useMediaQuery';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import { getWindowIds, getWorkspace } from '../state/selectors';
 import { WorkspaceAddButton } from '../components/WorkspaceAddButton';
 
+/**
+ * Be careful using this hook. It only works because the number of
+ * breakpoints in theme is static. It will break once you change the number of
+ * breakpoints. See https://legacy.reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
+ */
+function useWidth() {
+  const theme = useTheme();
+  const keys = [...theme.breakpoints.keys].reverse();
+  return (
+    keys.reduce((output, key) => {
+      // eslint-disable-next-line react-hooks/rules-of-hooks
+      const matches = useMediaQuery(theme.breakpoints.up(key));
+      return !output && matches ? key : output;
+    }, null) || 'xs'
+  );
+}
+
+/**
+ * withWidth
+ * @memberof WorkspaceControlPanel
+ * @private
+ */
+const withWidth = () => (WrappedComponent) => (props) => <WrappedComponent {...props} width={useWidth()} />;
+
 /**
  * mapStateToProps - to hook up connect
  * @memberof WorkspaceControlPanel
@@ -32,30 +56,8 @@ const mapStateToProps = (state, { width }) => {
  */
 const mapDispatchToProps = { setWorkspaceAddVisibility: actions.setWorkspaceAddVisibility };
 
-/**
- *
- * @param theme
- * @returns {{ctrlBtn: {margin: (number|string)}}}
- */
-const styles = theme => ({
-  fab: {
-    margin: theme.spacing(1),
-  },
-  fabPrimary: {
-    '&:focus': {
-      backgroundColor: theme.palette.primary.dark,
-    },
-  },
-  fabSecondary: {
-    '&:focus': {
-      backgroundColor: theme.palette.secondary.dark,
-    },
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   withWidth({ initialWidth: 'xs' }),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('WorkspaceAddButton'),
diff --git a/src/containers/WorkspaceArea.js b/src/containers/WorkspaceArea.js
index c2655978c98e9a934c485eccbf5984192b2aa31a..f58fa21317a454ecbeba92513635bb76dc634b74 100644
--- a/src/containers/WorkspaceArea.js
+++ b/src/containers/WorkspaceArea.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles, lighten, darken } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { WorkspaceArea } from '../components/WorkspaceArea';
 import { getConfig, getWindowIds, getWorkspace } from '../state/selectors';
@@ -20,30 +19,8 @@ const mapStateToProps = state => (
   }
 );
 
-/**
- *
- * @param theme
- * @returns {{background: {background: string}}}
- */
-const styles = (theme) => {
-  const getBackgroundColor = theme.palette.type === 'light' ? darken : lighten;
-
-  return {
-    viewer: {
-      background: getBackgroundColor(theme.palette.shades.light, 0.1),
-      bottom: 0,
-      left: 0,
-      overflow: 'hidden',
-      position: 'absolute',
-      right: 0,
-      top: 0,
-    },
-  };
-};
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps),
   withPlugins('WorkspaceArea'),
 );
diff --git a/src/containers/WorkspaceControlPanel.js b/src/containers/WorkspaceControlPanel.js
index 88f482e91d3a8cb92d78770c855eae6e7bda8907..e23bb417a950d24c6d7cb7bd6ec5bd690758e92b 100644
--- a/src/containers/WorkspaceControlPanel.js
+++ b/src/containers/WorkspaceControlPanel.js
@@ -1,69 +1,10 @@
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { WorkspaceControlPanel } from '../components/WorkspaceControlPanel';
 
-/**
- *
- * @param theme
- * @returns {{ctrlBtn: {margin: (number|string)},
- * drawer: {overflowX: string, height: string}}}
- */
-const styles = theme => ({
-  branding: {
-    display: 'flex',
-    position: 'absolute',
-    [theme.breakpoints.up('xs')]: {
-      display: 'none',
-    },
-    [theme.breakpoints.up('sm')]: {
-      bottom: 0,
-      display: 'block',
-      float: 'none',
-      right: 'auto',
-      width: '100%',
-    },
-    right: 0,
-  },
-  ctrlBtn: {
-    margin: theme.spacing(1),
-  },
-  drawer: {
-    overflowX: 'hidden',
-  },
-  root: {
-    height: 64,
-    [theme.breakpoints.up('sm')]: {
-      height: '100%',
-      left: 0,
-      right: 'auto',
-      width: 64,
-    },
-  },
-  toolbar: {
-    display: 'flex',
-    justifyContent: 'space-between',
-    [theme.breakpoints.up('sm')]: {
-      flexDirection: 'column',
-      justifyContent: 'flex-start',
-      minHeight: 0,
-    },
-  },
-  wide: {
-    width: 'auto',
-  },
-  workspaceButtons: {
-    [theme.breakpoints.up('sm')]: {
-      display: 'flex',
-      flexDirection: 'column',
-    },
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   withPlugins('WorkspaceControlPanel'),
   // further HOC go here
 );
diff --git a/src/containers/WorkspaceControlPanelButtons.js b/src/containers/WorkspaceControlPanelButtons.js
index eaef08bd775196782632a0bb6022759aa41b3d57..9d500357b4190a08d0a7b3a1a278fc067c06beb2 100644
--- a/src/containers/WorkspaceControlPanelButtons.js
+++ b/src/containers/WorkspaceControlPanelButtons.js
@@ -1,21 +1,8 @@
 import { compose } from 'redux';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { WorkspaceControlPanelButtons } from '../components/WorkspaceControlPanelButtons';
 
-/**
- *
- * @param theme
- * @returns {{ctrlBtn: {margin: (number|string)}}}
- */
-const styles = theme => ({
-  ctrlBtn: {
-    margin: theme.spacing(1),
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withPlugins('WorkspaceControlPanelButtons'),
 );
 
diff --git a/src/containers/WorkspaceElastic.js b/src/containers/WorkspaceElastic.js
index 9badc4614bbc259c42c3f64d6ca1654b37343fcc..5cc72f575697d02c3a32bdb5ddb7394ad1ffd505 100644
--- a/src/containers/WorkspaceElastic.js
+++ b/src/containers/WorkspaceElastic.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
 import WorkspaceElastic from '../components/WorkspaceElastic';
@@ -44,22 +43,7 @@ const mapDispatchToProps = (dispatch, props) => ({
   },
 });
 
-const styles = {
-  workspace: {
-    boxSizing: 'border-box',
-    margin: 0,
-    position: 'absolute',
-    transitionDuration: '.7s',
-    // order matters
-    // eslint-disable-next-line sort-keys
-    '& .react-draggable-dragging': {
-      transitionDuration: 'unset',
-    },
-  },
-};
-
 const enhance = compose(
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('WorkspaceElastic'),
   // further HOC go here
diff --git a/src/containers/WorkspaceElasticWindow.js b/src/containers/WorkspaceElasticWindow.js
index 1c071396f719be6aafabf396f8611b0bbab612c2..7e6b5ccac2ff2756781fd1a66208580554442e78 100644
--- a/src/containers/WorkspaceElasticWindow.js
+++ b/src/containers/WorkspaceElasticWindow.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core';
 import * as actions from '../state/actions';
 import WorkspaceElasticWindow from '../components/WorkspaceElasticWindow';
 import {
@@ -36,17 +35,7 @@ const mapDispatchToProps = (dispatch, props) => ({
   },
 });
 
-/**
- * @param theme
- */
-const styles = theme => ({
-  focused: {
-    zIndex: theme.zIndex.modal - 1,
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   // further HOC go here
 );
diff --git a/src/containers/WorkspaceExport.js b/src/containers/WorkspaceExport.js
index e1ac982c10aa03c0cff9451dd1c3fbb63bac98ab..069a52542815f19231609bdfe7e0f81997efbff7 100644
--- a/src/containers/WorkspaceExport.js
+++ b/src/containers/WorkspaceExport.js
@@ -1,6 +1,5 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core/styles';
 import { withTranslation } from 'react-i18next';
 import { withPlugins } from '../extend/withPlugins';
 import { WorkspaceExport } from '../components/WorkspaceExport';
@@ -17,18 +16,8 @@ const mapStateToProps = state => ({
   exportableState: getExportableState(state),
 });
 
-/**
- * Styles for the withStyles HOC
- */
-const styles = theme => ({
-  accordionTitle: {
-    padding: 0,
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, {}),
   withPlugins('WorkspaceExport'),
 );
diff --git a/src/containers/WorkspaceImport.js b/src/containers/WorkspaceImport.js
index 01c22d154776e0dff666ef3a28af1df9f5daaf1a..c529bca89a68af3d2f688ed4f4617670cf141076 100644
--- a/src/containers/WorkspaceImport.js
+++ b/src/containers/WorkspaceImport.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import { WorkspaceImport } from '../components/WorkspaceImport';
 import * as actions from '../state/actions';
@@ -16,22 +15,8 @@ const mapDispatchToProps = {
   importConfig: actions.importMiradorState,
 };
 
-/** */
-const styles = theme => ({
-  cancelBtn: {
-    color: theme.palette.text.primary,
-  },
-  textField: {
-    width: '100%',
-  },
-  textInput: {
-    fontFamily: 'monospace',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(null, mapDispatchToProps),
   withPlugins('WorkspaceImport'),
 );
diff --git a/src/containers/WorkspaceMenuButton.js b/src/containers/WorkspaceMenuButton.js
index 16e10d569baeeb4c63666db50e14fddf26cbeca5..b5f2518eb255db4cf81d47c6ab1b68d9ed602931 100644
--- a/src/containers/WorkspaceMenuButton.js
+++ b/src/containers/WorkspaceMenuButton.js
@@ -1,26 +1,10 @@
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import { WorkspaceMenuButton } from '../components/WorkspaceMenuButton';
 
-/**
- *
- * @param theme
- * @returns {{ctrlBtn: {margin: (number|string)}}}
- */
-const styles = theme => ({
-  ctrlBtn: {
-    margin: theme.spacing(1),
-  },
-  ctrlBtnSelected: {
-    backgroundColor: theme.palette.action.selected,
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   withPlugins('WorkspaceMenuButton'),
   // further HOC
 );
diff --git a/src/containers/WorkspaceMosaic.js b/src/containers/WorkspaceMosaic.js
index b66e2f4aa67fd4741712f7d9e131b052e693b9f6..4ab6529d059266edca949428ed7c0ff7a6c2b509 100644
--- a/src/containers/WorkspaceMosaic.js
+++ b/src/containers/WorkspaceMosaic.js
@@ -1,11 +1,9 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { getWorkspace } from '../state/selectors';
 import * as actions from '../state/actions';
 import { WorkspaceMosaic } from '../components/WorkspaceMosaic';
-import globalReactMosaicStyles from '../styles/react-mosaic-component';
 
 /**
  * mapStateToProps - to hook up connect
@@ -27,26 +25,7 @@ const mapStateToProps = state => (
  */
 const mapDispatchToProps = { updateWorkspaceMosaicLayout: actions.updateWorkspaceMosaicLayout };
 
-const styles = {
-  root: {
-    '& .mosaic-preview': {
-      boxShadow: 'none',
-    },
-    '& .mosaic-tile': {
-      boxShadow: '0 1px 3px 0 rgba(0, 0, 0, .2), 0 1px 1px 0 rgba(0, 0, 0, .2), 0 2px 1px -1px rgba(0, 0, 0, .2)',
-    },
-    '& .mosaic-window': {
-      boxShadow: 'none',
-    },
-    '& .mosaic-window-toolbar': {
-      display: 'none !important',
-    },
-  },
-  ...globalReactMosaicStyles,
-};
-
 const enhance = compose(
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('WorkspaceMosaic'),
   // further HOC go here
diff --git a/src/containers/WorkspaceOptionsButton.js b/src/containers/WorkspaceOptionsButton.js
index f17b51310f56018393b23b6593ff87da902f2857..5768c4cd2aae646aef2e586106f357cd3856fd59 100644
--- a/src/containers/WorkspaceOptionsButton.js
+++ b/src/containers/WorkspaceOptionsButton.js
@@ -1,24 +1,9 @@
 import { compose } from 'redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core/styles';
 import { withPlugins } from '../extend/withPlugins';
 import { WorkspaceOptionsButton } from '../components/WorkspaceOptionsButton';
 
-/**
- *
- * @param theme
- */
-const styles = theme => ({
-  ctrlBtn: {
-    margin: theme.spacing(1),
-  },
-  ctrlBtnSelected: {
-    backgroundColor: theme.palette.action.selected,
-  },
-});
-
 const enhance = compose(
-  withStyles(styles),
   withTranslation(),
   withPlugins('WorkspaceOptionsButton'),
 );
diff --git a/src/containers/WorkspaceSelectionDialog.js b/src/containers/WorkspaceSelectionDialog.js
index d14881af77bf8f0a0a894d50cf82b821910c037f..3305e5321672755ccd59391bc0d61d330e5b17a5 100644
--- a/src/containers/WorkspaceSelectionDialog.js
+++ b/src/containers/WorkspaceSelectionDialog.js
@@ -1,7 +1,6 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import { WorkspaceSelectionDialog } from '../components/WorkspaceSelectionDialog';
 import * as actions from '../state/actions';
@@ -23,60 +22,8 @@ const mapDispatchToProps = {
  */
 const mapStateToProps = state => ({ workspaceType: getWorkspaceType(state) });
 
-/** */
-const styles = theme => ({
-  card: {
-    backgroundColor: 'transparent',
-    borderRadius: '0',
-    boxShadow: '0 0 transparent',
-    display: 'flex',
-  },
-  content: {
-    flex: '1 0 auto',
-  },
-  details: {
-    display: 'flex',
-    flexDirection: 'column',
-  },
-  headline: {
-    paddingBottom: '6px',
-  },
-  list: {
-    '&active': {
-      outline: 'none',
-    },
-    '&focus': {
-      outline: 'none',
-    },
-    outline: 'none',
-  },
-  media: {
-    flex: '0 0 120px',
-    height: '90px',
-  },
-  menuItem: {
-    height: 'auto',
-    overflow: 'auto',
-    whiteSpace: 'inherit',
-  },
-  root: {
-    '&:last-child': {
-      paddingBottom: '12px',
-    },
-    paddingBottom: 0,
-    paddingTop: 0,
-    textAlign: 'left',
-  },
-  svgIcon: {
-    flexShrink: 0,
-    height: '90px',
-    width: '120px',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('WorkspaceSelectionDialog'),
 );
diff --git a/src/containers/ZoomControls.js b/src/containers/ZoomControls.js
index 512ce860cbef74cb3534084c3d8ba9d0e06db0bc..1cc85d545509720db14d9af2c07a189a5e10b7a6 100644
--- a/src/containers/ZoomControls.js
+++ b/src/containers/ZoomControls.js
@@ -1,10 +1,9 @@
 import { compose } from 'redux';
 import { connect } from 'react-redux';
 import { withTranslation } from 'react-i18next';
-import { withStyles } from '@material-ui/core';
 import { withPlugins } from '../extend/withPlugins';
 import * as actions from '../state/actions';
-import { getShowZoomControlsConfig, getViewer } from '../state/selectors';
+import { getViewer } from '../state/selectors';
 import { ZoomControls } from '../components/ZoomControls';
 
 /**
@@ -14,7 +13,6 @@ import { ZoomControls } from '../components/ZoomControls';
  */
 const mapStateToProps = (state, { windowId }) => (
   {
-    showZoomControls: getShowZoomControlsConfig(state),
     viewer: getViewer(state, { windowId }),
   }
 );
@@ -26,33 +24,8 @@ const mapStateToProps = (state, { windowId }) => (
  */
 const mapDispatchToProps = { updateViewport: actions.updateViewport };
 
-/**
- *
- * @param theme
- * @returns {{zoom_controls: {position: string, right: number},
- * ListItem: {paddingBottom: number, paddingTop: number}}}
- */
-const styles = theme => ({
-  divider: {
-    borderRight: '1px solid #808080',
-    display: 'inline-block',
-    height: '24px',
-    margin: '12px 6px',
-  },
-  ListItem: {
-    paddingBottom: 0,
-    paddingTop: 0,
-  },
-  zoom_controls: {
-    display: 'flex',
-    flexDirection: 'row',
-    justifyContent: 'center',
-  },
-});
-
 const enhance = compose(
   withTranslation(),
-  withStyles(styles),
   connect(mapStateToProps, mapDispatchToProps),
   withPlugins('ZoomControls'),
 );
diff --git a/src/extend/pluginMapping.js b/src/extend/pluginMapping.js
index efc449252abff501d89a04062516592fe7c2dd9b..7ddeefd6bb9c6e88f9cb1134abb0f66dffef05c6 100644
--- a/src/extend/pluginMapping.js
+++ b/src/extend/pluginMapping.js
@@ -18,7 +18,7 @@ import CompanionWindowRegistry from '../lib/CompanionWindowRegistry';
  */
 export function createTargetToPluginMapping(plugins) {
   return plugins.reduce((map, plugin) => (
-    update(map, [plugin.target, plugin.mode], x => [...x || [], plugin])
+    update(map, [plugin.target, plugin.mode], x => [...(x || []), plugin])
   ), {});
 }
 
diff --git a/src/state/createStore.js b/src/state/createStore.js
index 9467f322c5535aab6d73abcd48d0aaed5b3dc9a1..c115859260c6db7cd5398b22b308bf9572cf5b32 100644
--- a/src/state/createStore.js
+++ b/src/state/createStore.js
@@ -6,7 +6,7 @@
 import thunkMiddleware from 'redux-thunk';
 import createSagaMiddleware from 'redux-saga';
 import { combineReducers, createStore, applyMiddleware } from 'redux';
-import { composeWithDevTools } from 'redux-devtools-extension';
+import { composeWithDevTools } from '@redux-devtools/extension';
 import createRootReducer from './reducers/rootReducer';
 import getRootSaga from './sagas';
 import settings from '../config/settings';
diff --git a/src/styles/react-mosaic-component.js b/src/styles/react-mosaic-component.js
index 23d46a4fb2c67f5531ab4c4e4a2fc01c3c464110..2f6885ea1208517f1943c303366875083a3d4bfd 100644
--- a/src/styles/react-mosaic-component.js
+++ b/src/styles/react-mosaic-component.js
@@ -1,285 +1,283 @@
 // Generated using jss convert node_modules/react-mosaic-component/react-mosaic-component.css > src/styles/react-mosaic-component.js
 // .mosaic-blueprint-theme styles have also been removed
 const globalReactMosaicStyles = {
-  '@global': {
-    '.mosaic': {
-      height: '100%',
-      width: '100%',
-    },
-    '.mosaic, .mosaic > *': {
-      boxSizing: 'border-box',
-    },
-    '.mosaic .mosaic-zero-state': {
-      position: 'absolute',
-      top: 6,
-      right: 6,
-      bottom: 6,
-      left: 6,
-      width: 'auto',
-      height: 'auto',
-      zIndex: '1',
-    },
-    '.mosaic-root': {
-      position: 'absolute',
-      top: 3,
-      right: 3,
-      bottom: 3,
-      left: 3,
-    },
-    '.mosaic-split': {
-      position: 'absolute',
-      zIndex: '1',
-      touchAction: 'none',
-    },
-    '.mosaic-split:hover': {
-      background: 'black',
-    },
-    '.mosaic-split .mosaic-split-line': {
-      position: 'absolute',
-    },
-    '.mosaic-split.-row': {
-      marginLeft: -3,
-      width: 6,
-      cursor: 'ew-resize',
-    },
-    '.mosaic-split.-row .mosaic-split-line': {
-      top: '0',
-      bottom: '0',
-      left: 3,
-      right: 3,
-    },
-    '.mosaic-split.-column': {
-      marginTop: -3,
-      height: 6,
-      cursor: 'ns-resize',
-    },
-    '.mosaic-split.-column .mosaic-split-line': {
-      top: 3,
-      bottom: 3,
-      left: '0',
-      right: '0',
-    },
-    '.mosaic-tile': {
-      position: 'absolute',
-      margin: 3,
-    },
-    '.mosaic-tile > *': {
-      height: '100%',
-      width: '100%',
-    },
-    '.mosaic-drop-target': {
-      position: 'relative',
-    },
-    '.mosaic-drop-target.drop-target-hover .drop-target-container': {
-      display: 'block',
-    },
-    '.mosaic-drop-target.mosaic > .drop-target-container .drop-target.left': {
-      right: 'calc(100% -  10px )',
-    },
-    '.mosaic-drop-target.mosaic > .drop-target-container .drop-target.right': {
-      left: 'calc(100% -  10px )',
-    },
-    '.mosaic-drop-target.mosaic > .drop-target-container .drop-target.bottom': {
-      top: 'calc(100% -  10px )',
-    },
-    '.mosaic-drop-target.mosaic > .drop-target-container .drop-target.top': {
-      bottom: 'calc(100% -  10px )',
-    },
-    '.mosaic-drop-target .drop-target-container': {
-      position: 'absolute',
-      top: '0',
-      right: '0',
-      bottom: '0',
-      left: '0',
-      display: 'none',
-    },
-    '.mosaic-drop-target .drop-target-container.-dragging': {
-      display: 'block',
-    },
-    '.mosaic-drop-target .drop-target-container .drop-target': {
-      position: 'absolute',
-      top: '0',
-      right: '0',
-      bottom: '0',
-      left: '0',
-      background: 'rgba(0, 0, 0, 0.2)',
-      border: '2px solid black',
-      opacity: '0',
-      zIndex: '5',
-    },
-    '.mosaic-drop-target .drop-target-container .drop-target.left': {
-      right: 'calc(100% -  30% )',
-    },
-    '.mosaic-drop-target .drop-target-container .drop-target.right': {
-      left: 'calc(100% -  30% )',
-    },
-    '.mosaic-drop-target .drop-target-container .drop-target.bottom': {
-      top: 'calc(100% -  30% )',
-    },
-    '.mosaic-drop-target .drop-target-container .drop-target.top': {
-      bottom: 'calc(100% -  30% )',
-    },
-    '.mosaic-drop-target .drop-target-container .drop-target.drop-target-hover': {
-      opacity: '1',
-    },
-    '.mosaic-drop-target .drop-target-container .drop-target.drop-target-hover.left': {
-      right: 'calc(100% -  50% )',
-    },
-    '.mosaic-drop-target .drop-target-container .drop-target.drop-target-hover.right': {
-      left: 'calc(100% -  50% )',
-    },
-    '.mosaic-drop-target .drop-target-container .drop-target.drop-target-hover.bottom': {
-      top: 'calc(100% -  50% )',
-    },
-    '.mosaic-drop-target .drop-target-container .drop-target.drop-target-hover.top': {
-      bottom: 'calc(100% -  50% )',
-    },
-    '.mosaic-window, .mosaic-preview': {
-      position: 'relative',
-      display: 'flex',
-      fallbacks: [
-        {
-          display: '-webkit-box',
-        },
-      ],
-      webkitBoxOrient: 'vertical',
-      webkitBoxDirection: 'normal',
-      flexDirection: 'column',
-      overflow: 'hidden',
-      boxShadow: '0 0 1px rgba(0, 0, 0, 0.2)',
-    },
-    '.mosaic-window .mosaic-window-toolbar, .mosaic-preview .mosaic-window-toolbar': {
-      zIndex: '4',
-      display: 'flex',
-      fallbacks: [
-        {
-          display: '-webkit-box',
-        },
-      ],
-      webkitBoxPack: 'justify',
-      justifyContent: 'space-between',
-      webkitBoxAlign: 'center',
-      alignItems: 'center',
-      flexShrink: '0',
-      height: 30,
-      background: 'white',
-      boxShadow: '0 1px 1px rgba(0, 0, 0, 0.2)',
-    },
-    '.mosaic-window .mosaic-window-toolbar.draggable, .mosaic-preview .mosaic-window-toolbar.draggable': {
-      cursor: 'move',
-    },
-    '.mosaic-window .mosaic-window-title, .mosaic-preview .mosaic-window-title': {
-      paddingLeft: 15,
-      webkitBoxFlex: '1',
-      flex: '1',
-      textOverflow: 'ellipsis',
-      whiteSpace: 'nowrap',
-      overflow: 'hidden',
-      minHeight: 18,
-    },
-    '.mosaic-window .mosaic-window-controls, .mosaic-preview .mosaic-window-controls': {
-      display: 'flex',
-      fallbacks: [
-        {
-          display: '-webkit-box',
-        },
-      ],
-      height: '100%',
-    },
-    '.mosaic-window .mosaic-window-controls .separator, .mosaic-preview .mosaic-window-controls .separator': {
-      height: 20,
-      borderLeft: '1px solid black',
-      margin: '5px 4px',
-    },
-    '.mosaic-window .mosaic-window-body, .mosaic-preview .mosaic-window-body': {
-      position: 'relative',
-      webkitBoxFlex: '1',
-      flex: '1',
-      height: '0',
-      background: 'white',
-      zIndex: '1',
-      overflow: 'hidden',
-    },
-    '.mosaic-window .mosaic-window-additional-actions-bar, .mosaic-preview .mosaic-window-additional-actions-bar': {
-      position: 'absolute',
-      top: 30,
-      right: '0',
-      bottom: 'initial',
-      left: '0',
-      height: '0',
-      overflow: 'hidden',
-      background: 'white',
-      webkitBoxPack: 'end',
-      justifyContent: 'flex-end',
-      display: 'flex',
-      fallbacks: [
-        {
-          display: '-webkit-box',
-        },
-      ],
-      zIndex: '3',
-    },
-    '.mosaic-window .mosaic-window-additional-actions-bar .bp3-button, .mosaic-preview .mosaic-window-additional-actions-bar .bp3-button': {
-      margin: '0',
-    },
-    '.mosaic-window .mosaic-window-additional-actions-bar .bp3-button:after, .mosaic-preview .mosaic-window-additional-actions-bar .bp3-button:after': {
-      display: 'none',
-    },
-    '.mosaic-window .mosaic-window-body-overlay, .mosaic-preview .mosaic-window-body-overlay': {
-      position: 'absolute',
-      top: '0',
-      right: '0',
-      bottom: '0',
-      left: '0',
-      opacity: '0',
-      background: 'white',
-      display: 'none',
-      zIndex: '2',
-    },
-    '.mosaic-window.additional-controls-open .mosaic-window-additional-actions-bar, .mosaic-preview.additional-controls-open .mosaic-window-additional-actions-bar': {
-      height: 30,
-    },
-    '.mosaic-window.additional-controls-open .mosaic-window-body-overlay, .mosaic-preview.additional-controls-open .mosaic-window-body-overlay': {
-      display: 'block',
-    },
-    '.mosaic-window .mosaic-preview, .mosaic-preview .mosaic-preview': {
-      height: '100%',
-      width: '100%',
-      position: 'absolute',
-      zIndex: '0',
-      border: '1px solid black',
-      maxHeight: 400,
-    },
-    '.mosaic-window .mosaic-preview .mosaic-window-body, .mosaic-preview .mosaic-preview .mosaic-window-body': {
-      display: 'flex',
-      fallbacks: [
-        {
-          display: '-webkit-box',
-        },
-      ],
-      webkitBoxOrient: 'vertical',
-      webkitBoxDirection: 'normal',
-      flexDirection: 'column',
-      webkitBoxAlign: 'center',
-      alignItems: 'center',
-      webkitBoxPack: 'center',
-      justifyContent: 'center',
-    },
-    '.mosaic-window .mosaic-preview h4, .mosaic-preview .mosaic-preview h4': {
-      marginBottom: 10,
-    },
-    '.mosaic:not(.mosaic-blueprint-theme) .mosaic-default-control.close-button:before': {
-      content: '\'Close\'',
-    },
-    '.mosaic:not(.mosaic-blueprint-theme) .mosaic-default-control.split-button:before': {
-      content: '\'Split\'',
-    },
-    '.mosaic:not(.mosaic-blueprint-theme) .mosaic-default-control.replace-button:before': {
-      content: '\'Replace\'',
-    },
-    '.mosaic:not(.mosaic-blueprint-theme) .mosaic-default-control.expand-button:before': {
-      content: '\'Expand\'',
-    },
+  '.mosaic': {
+    height: '100%',
+    width: '100%',
+  },
+  '.mosaic, .mosaic > *': {
+    boxSizing: 'border-box',
+  },
+  '.mosaic .mosaic-zero-state': {
+    position: 'absolute',
+    top: 6,
+    right: 6,
+    bottom: 6,
+    left: 6,
+    width: 'auto',
+    height: 'auto',
+    zIndex: '1',
+  },
+  '.mosaic-root': {
+    position: 'absolute',
+    top: 3,
+    right: 3,
+    bottom: 3,
+    left: 3,
+  },
+  '.mosaic-split': {
+    position: 'absolute',
+    zIndex: '1',
+    touchAction: 'none',
+  },
+  '.mosaic-split:hover': {
+    background: 'black',
+  },
+  '.mosaic-split .mosaic-split-line': {
+    position: 'absolute',
+  },
+  '.mosaic-split.-row': {
+    marginLeft: -3,
+    width: 6,
+    cursor: 'ew-resize',
+  },
+  '.mosaic-split.-row .mosaic-split-line': {
+    top: '0',
+    bottom: '0',
+    left: 3,
+    right: 3,
+  },
+  '.mosaic-split.-column': {
+    marginTop: -3,
+    height: 6,
+    cursor: 'ns-resize',
+  },
+  '.mosaic-split.-column .mosaic-split-line': {
+    top: 3,
+    bottom: 3,
+    left: '0',
+    right: '0',
+  },
+  '.mosaic-tile': {
+    position: 'absolute',
+    margin: 3,
+  },
+  '.mosaic-tile > *': {
+    height: '100%',
+    width: '100%',
+  },
+  '.mosaic-drop-target': {
+    position: 'relative',
+  },
+  '.mosaic-drop-target.drop-target-hover .drop-target-container': {
+    display: 'block',
+  },
+  '.mosaic-drop-target.mosaic > .drop-target-container .drop-target.left': {
+    right: 'calc(100% -  10px )',
+  },
+  '.mosaic-drop-target.mosaic > .drop-target-container .drop-target.right': {
+    left: 'calc(100% -  10px )',
+  },
+  '.mosaic-drop-target.mosaic > .drop-target-container .drop-target.bottom': {
+    top: 'calc(100% -  10px )',
+  },
+  '.mosaic-drop-target.mosaic > .drop-target-container .drop-target.top': {
+    bottom: 'calc(100% -  10px )',
+  },
+  '.mosaic-drop-target .drop-target-container': {
+    position: 'absolute',
+    top: '0',
+    right: '0',
+    bottom: '0',
+    left: '0',
+    display: 'none',
+  },
+  '.mosaic-drop-target .drop-target-container.-dragging': {
+    display: 'block',
+  },
+  '.mosaic-drop-target .drop-target-container .drop-target': {
+    position: 'absolute',
+    top: '0',
+    right: '0',
+    bottom: '0',
+    left: '0',
+    background: 'rgba(0, 0, 0, 0.2)',
+    border: '2px solid black',
+    opacity: '0',
+    zIndex: '5',
+  },
+  '.mosaic-drop-target .drop-target-container .drop-target.left': {
+    right: 'calc(100% -  30% )',
+  },
+  '.mosaic-drop-target .drop-target-container .drop-target.right': {
+    left: 'calc(100% -  30% )',
+  },
+  '.mosaic-drop-target .drop-target-container .drop-target.bottom': {
+    top: 'calc(100% -  30% )',
+  },
+  '.mosaic-drop-target .drop-target-container .drop-target.top': {
+    bottom: 'calc(100% -  30% )',
+  },
+  '.mosaic-drop-target .drop-target-container .drop-target.drop-target-hover': {
+    opacity: '1',
+  },
+  '.mosaic-drop-target .drop-target-container .drop-target.drop-target-hover.left': {
+    right: 'calc(100% -  50% )',
+  },
+  '.mosaic-drop-target .drop-target-container .drop-target.drop-target-hover.right': {
+    left: 'calc(100% -  50% )',
+  },
+  '.mosaic-drop-target .drop-target-container .drop-target.drop-target-hover.bottom': {
+    top: 'calc(100% -  50% )',
+  },
+  '.mosaic-drop-target .drop-target-container .drop-target.drop-target-hover.top': {
+    bottom: 'calc(100% -  50% )',
+  },
+  '.mosaic-window, .mosaic-preview': {
+    position: 'relative',
+    display: 'flex',
+    fallbacks: [
+      {
+        display: '-webkit-box',
+      },
+    ],
+    webkitBoxOrient: 'vertical',
+    webkitBoxDirection: 'normal',
+    flexDirection: 'column',
+    overflow: 'hidden',
+    boxShadow: '0 0 1px rgba(0, 0, 0, 0.2)',
+  },
+  '.mosaic-window .mosaic-window-toolbar, .mosaic-preview .mosaic-window-toolbar': {
+    zIndex: '4',
+    display: 'flex',
+    fallbacks: [
+      {
+        display: '-webkit-box',
+      },
+    ],
+    webkitBoxPack: 'justify',
+    justifyContent: 'space-between',
+    webkitBoxAlign: 'center',
+    alignItems: 'center',
+    flexShrink: '0',
+    height: 30,
+    background: 'white',
+    boxShadow: '0 1px 1px rgba(0, 0, 0, 0.2)',
+  },
+  '.mosaic-window .mosaic-window-toolbar.draggable, .mosaic-preview .mosaic-window-toolbar.draggable': {
+    cursor: 'move',
+  },
+  '.mosaic-window .mosaic-window-title, .mosaic-preview .mosaic-window-title': {
+    paddingLeft: 15,
+    webkitBoxFlex: '1',
+    flex: '1',
+    textOverflow: 'ellipsis',
+    whiteSpace: 'nowrap',
+    overflow: 'hidden',
+    minHeight: 18,
+  },
+  '.mosaic-window .mosaic-window-controls, .mosaic-preview .mosaic-window-controls': {
+    display: 'flex',
+    fallbacks: [
+      {
+        display: '-webkit-box',
+      },
+    ],
+    height: '100%',
+  },
+  '.mosaic-window .mosaic-window-controls .separator, .mosaic-preview .mosaic-window-controls .separator': {
+    height: 20,
+    borderLeft: '1px solid black',
+    margin: '5px 4px',
+  },
+  '.mosaic-window .mosaic-window-body, .mosaic-preview .mosaic-window-body': {
+    position: 'relative',
+    webkitBoxFlex: '1',
+    flex: '1',
+    height: '0',
+    background: 'white',
+    zIndex: '1',
+    overflow: 'hidden',
+  },
+  '.mosaic-window .mosaic-window-additional-actions-bar, .mosaic-preview .mosaic-window-additional-actions-bar': {
+    position: 'absolute',
+    top: 30,
+    right: '0',
+    bottom: 'initial',
+    left: '0',
+    height: '0',
+    overflow: 'hidden',
+    background: 'white',
+    webkitBoxPack: 'end',
+    justifyContent: 'flex-end',
+    display: 'flex',
+    fallbacks: [
+      {
+        display: '-webkit-box',
+      },
+    ],
+    zIndex: '3',
+  },
+  '.mosaic-window .mosaic-window-additional-actions-bar .bp3-button, .mosaic-preview .mosaic-window-additional-actions-bar .bp3-button': {
+    margin: '0',
+  },
+  '.mosaic-window .mosaic-window-additional-actions-bar .bp3-button:after, .mosaic-preview .mosaic-window-additional-actions-bar .bp3-button:after': {
+    display: 'none',
+  },
+  '.mosaic-window .mosaic-window-body-overlay, .mosaic-preview .mosaic-window-body-overlay': {
+    position: 'absolute',
+    top: '0',
+    right: '0',
+    bottom: '0',
+    left: '0',
+    opacity: '0',
+    background: 'white',
+    display: 'none',
+    zIndex: '2',
+  },
+  '.mosaic-window.additional-controls-open .mosaic-window-additional-actions-bar, .mosaic-preview.additional-controls-open .mosaic-window-additional-actions-bar': {
+    height: 30,
+  },
+  '.mosaic-window.additional-controls-open .mosaic-window-body-overlay, .mosaic-preview.additional-controls-open .mosaic-window-body-overlay': {
+    display: 'block',
+  },
+  '.mosaic-window .mosaic-preview, .mosaic-preview .mosaic-preview': {
+    height: '100%',
+    width: '100%',
+    position: 'absolute',
+    zIndex: '0',
+    border: '1px solid black',
+    maxHeight: 400,
+  },
+  '.mosaic-window .mosaic-preview .mosaic-window-body, .mosaic-preview .mosaic-preview .mosaic-window-body': {
+    display: 'flex',
+    fallbacks: [
+      {
+        display: '-webkit-box',
+      },
+    ],
+    webkitBoxOrient: 'vertical',
+    webkitBoxDirection: 'normal',
+    flexDirection: 'column',
+    webkitBoxAlign: 'center',
+    alignItems: 'center',
+    webkitBoxPack: 'center',
+    justifyContent: 'center',
+  },
+  '.mosaic-window .mosaic-preview h4, .mosaic-preview .mosaic-preview h4': {
+    marginBottom: 10,
+  },
+  '.mosaic:not(.mosaic-blueprint-theme) .mosaic-default-control.close-button:before': {
+    content: '\'Close\'',
+  },
+  '.mosaic:not(.mosaic-blueprint-theme) .mosaic-default-control.split-button:before': {
+    content: '\'Split\'',
+  },
+  '.mosaic:not(.mosaic-blueprint-theme) .mosaic-default-control.replace-button:before': {
+    content: '\'Replace\'',
+  },
+  '.mosaic:not(.mosaic-blueprint-theme) .mosaic-default-control.expand-button:before': {
+    content: '\'Expand\'',
   },
 };