Repository: datalayer/jupyter-ui (language: python)

Issue:
Document instructions for linting and prettier



Discussion / hints:

Fix patch:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..503a617d
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,56 @@
+# How to contribute?
+
+If you are reading this file, you have some ideas to improve this code; thanks a lot for that.
+
+Datalayer welcomes all contributions: issue reporting, documentation improvements, bug fixes
+or code enhancements.
+
+## Development
+
+We will focus here on the `packages/react` folder that is the corner stone of jupyter-ui; aka
+providing Jupyter React components.
+
+### Installation
+
+To install it in dev mode, you first must install:
+- [node.js](https://nodejs.org) (preferably the LTS version)
+
+Then execute the following commands in the `packages/react` folder:
+
+```sh
+# Install yarn - https://yarnpkg.com/getting-started/install
+corepack enable
+yarn install
+yarn build
+```
+
+### Code changes
+
+The best way to test your changes is to use the storybook - a third-party tool allowing to
+interact with an isolated component.  
+To start it, execute
+
+```sh
+yarn storybook
+```
+
+It should open a web browser tab pointing to `http://localhost:6006` in which you will
+be able to pick a story in the left sidebar.
+
+You can now change the code of the component and the storybook will get updated right
+away when you save the source code.
+
+**FAQ**:
+
+- *No story available* for a component?  
+  You can create a story for a component by adding a new file `*.stories.tsx` in the folder `packages/react/stories`.
+  Hint: start by copying the file `Console.stories.tsx`
+
+### Linting the code
+
+The code follows some rules for format and prevent bad practices.
+To check that and apply auto fixes, you must execute:
+
+```sh
+yarn lint
+```
diff --git a/packages/react/package.json b/packages/react/package.json
index c2e71d2a..f1f967e6 100644
--- a/packages/react/package.json
+++ b/packages/react/package.json
@@ -194,15 +194,15 @@
     "@types/styled-components": "5.1.26",
     "@types/uuid": "8.3.0",
     "@types/webpack-env": "1.18.2",
-    "@typescript-eslint/eslint-plugin": "4.8.1",
-    "@typescript-eslint/parser": "4.8.1",
+    "@typescript-eslint/eslint-plugin": "^6.1.0",
+    "@typescript-eslint/parser": "^6.1.0",
     "babel-loader": "9.1.2",
     "bundle-loader": "0.5.6",
     "cross-env": "7.0.3",
     "css-loader": "5.2.4",
-    "eslint": "7.14.0",
-    "eslint-config-prettier": "6.15.0",
-    "eslint-plugin-prettier": "3.1.4",
+    "eslint": "^8.36.0",
+    "eslint-config-prettier": "^8.8.0",
+    "eslint-plugin-prettier": "^5.0.0",
     "gulp": "4.0.2",
     "gulp-append-prepend": "1.0.8",
     "gulp-filter": "6.0.0",
@@ -214,7 +214,7 @@
     "jupyterlab-plotly": "5.17.0",
     "mkdirp": "1.0.3",
     "npm-run-all": "4.1.5",
-    "prettier": "2.1.1",
+    "prettier": "3.0.0",
     "process": "0.11.10",
     "react-sparklines": "1.7.0",
     "rimraf": "3.0.2",
@@ -222,11 +222,11 @@
     "stream": "0.0.2",
     "stream-browserify": "2.0.2",
     "style-loader": "2.0.0",
-    "stylelint": "14.3.0",
-    "stylelint-config-prettier": "9.0.4",
-    "stylelint-config-recommended": "6.0.0",
-    "stylelint-config-standard": "~24.0.0",
-    "stylelint-prettier": "2.0.0",
+    "stylelint": "^15.10.1",
+    "stylelint-config-recommended": "^13.0.0",
+    "stylelint-config-standard": "^34.0.0",
+    "stylelint-csstree-validator": "^3.0.0",
+    "stylelint-prettier": "^4.0.0",
     "svg-url-loader": "7.1.1",
     "ts-jest": "29.0.5",
     "ts-loader": "^9.4.3",
@@ -277,5 +277,81 @@
         "yarn clean:all"
       ]
     }
+  },
+  "eslintIgnore": [
+    "node_modules",
+    "dist",
+    "coverage",
+    "**/*.d.ts",
+    "tests",
+    "**/__tests__",
+    "stories",
+    "playwright.config.ts"
+  ],
+  "eslintConfig": {
+    "extends": [
+      "eslint:recommended",
+      "plugin:@typescript-eslint/eslint-recommended",
+      "plugin:@typescript-eslint/recommended",
+      "plugin:prettier/recommended"
+    ],
+    "parser": "@typescript-eslint/parser",
+    "parserOptions": {
+      "project": "tsconfig.json",
+      "sourceType": "module"
+    },
+    "plugins": [
+      "@typescript-eslint"
+    ],
+    "rules": {
+      "@typescript-eslint/no-unused-vars": [
+        "warn",
+        {
+          "args": "none"
+        }
+      ],
+      "@typescript-eslint/no-explicit-any": "off",
+      "@typescript-eslint/no-namespace": "off",
+      "@typescript-eslint/no-use-before-define": "off",
+      "@typescript-eslint/quotes": [
+        "error",
+        "single",
+        {
+          "avoidEscape": true,
+          "allowTemplateLiterals": false
+        }
+      ],
+      "curly": [
+        "error",
+        "all"
+      ],
+      "eqeqeq": "error",
+      "prefer-arrow-callback": "error"
+    }
+  },
+  "prettier": {
+    "singleQuote": true,
+    "arrowParens": "avoid",
+    "bracketSpacing": true,
+    "jsxSingleQuote": false,
+    "printWidth": 80,
+    "trailingComma": "es5"
+  },
+  "stylelint": {
+    "extends": [
+      "stylelint-config-recommended",
+      "stylelint-config-standard",
+      "stylelint-prettier/recommended"
+    ],
+    "plugins": [
+      "stylelint-csstree-validator"
+    ],
+    "rules": {
+      "csstree/validator": true,
+      "property-no-vendor-prefix": null,
+      "selector-class-pattern": "^([a-z][A-z\\d]*)(-[A-z\\d]+)*$",
+      "selector-no-vendor-prefix": null,
+      "value-no-vendor-prefix": null
+    }
   }
 }
diff --git a/packages/react/playwright.config.ts b/packages/react/playwright.config.ts
index f57ae8ce..ff3342f0 100644
--- a/packages/react/playwright.config.ts
+++ b/packages/react/playwright.config.ts
@@ -15,22 +15,23 @@ const config: PlaywrightTestConfig = {
     url: 'http://localhost:6006/iframe.html?id=components-console--default',
     timeout: 5 * 60 * 1000,
     // It is safe to reuse the server for stories testing
-    reuseExistingServer: true
+    reuseExistingServer: true,
   },
   use: {
     baseURL: process.env.TARGET_URL ?? 'http://localhost:6006',
     trace: 'on-first-retry',
+    video: process.env.CI ? 'off' : 'retain-on-failure',
   },
   projects: [
     {
       name: 'chromium',
-      use: { ...devices['Desktop Chrome'] }
+      use: { ...devices['Desktop Chrome'] },
     },
   ],
   reporter: [
     [process.env.CI ? 'github' : 'list'],
-    ['html', { open: process.env.CI ? 'never' : 'on-failure' }]
-  ]
+    ['html', { open: process.env.CI ? 'never' : 'on-failure' }],
+  ],
 };
 
-export default config;
\ No newline at end of file
+export default config;
diff --git a/packages/react/src/app/tabs/components/NotebookComponent.tsx b/packages/react/src/app/tabs/components/NotebookComponent.tsx
index 445022a8..85f1e281 100644
--- a/packages/react/src/app/tabs/components/NotebookComponent.tsx
+++ b/packages/react/src/app/tabs/components/NotebookComponent.tsx
@@ -11,7 +11,8 @@
 
 const NotebookComponent = () => {
   return (
-    <>{/*
+    <>
+      {/*
       <Notebook
         nbformat={nbformat}
         uid="notebook-uid"
@@ -19,7 +20,8 @@ const NotebookComponent = () => {
         height="calc(100vh - 2.6rem)" // (Height - Toolbar Height).
         CellSidebar={CellSidebarNew}
       />
-  */}</>
+  */}
+    </>
   );
 };
 
diff --git a/packages/react/src/components/cell/Cell.tsx b/packages/react/src/components/cell/Cell.tsx
index b5aa14ed..f8e077a1 100644
--- a/packages/react/src/components/cell/Cell.tsx
+++ b/packages/react/src/components/cell/Cell.tsx
@@ -47,7 +47,7 @@ export type ICellProps = {
 };
 
 export const Cell = (props: ICellProps) => {
-  const { source, autoStart } = props;
+  const { source = '', autoStart } = props;
   const { serverSettings, injectableStore, defaultKernel } = useJupyter();
   const dispatch = useDispatch();
   const [adapter, setAdapter] = useState<CellAdapter>();
@@ -55,7 +55,7 @@ export const Cell = (props: ICellProps) => {
     injectableStore.inject('cell', cellReducer);
   }, []);
   useEffect(() => {
-    if (source && defaultKernel) {
+    if (defaultKernel) {
       defaultKernel.ready.then(() => {
         const adapter = new CellAdapter({
           source,
diff --git a/packages/react/src/components/cell/CellCommands.ts b/packages/react/src/components/cell/CellCommands.ts
index 7f2e313e..bc93f421 100644
--- a/packages/react/src/components/cell/CellCommands.ts
+++ b/packages/react/src/components/cell/CellCommands.ts
@@ -43,7 +43,7 @@ export const CellCommands = (
   });
   const bindings = [
     {
-      selector: `.jp-InputArea-editor.jp-mod-completer-active`,
+      selector: '.jp-InputArea-editor.jp-mod-completer-active',
       keys: ['Enter'],
       command: cmdIds.select,
     },
diff --git a/packages/react/src/components/codemirror/CodeMirrorEditor.tsx b/packages/react/src/components/codemirror/CodeMirrorEditor.tsx
index 16a53b11..6166d7d8 100644
--- a/packages/react/src/components/codemirror/CodeMirrorEditor.tsx
+++ b/packages/react/src/components/codemirror/CodeMirrorEditor.tsx
@@ -89,7 +89,6 @@ export const CodeMirrorEditor = (props: {
         source: code,
       })
     );
-    let editorView: EditorView;
     const language = new Compartment();
     const keyBinding = [
       {
@@ -119,7 +118,7 @@ export const CodeMirrorEditor = (props: {
         }),
       ],
     });
-    editorView = new EditorView({
+    const editorView = new EditorView({
       state: state,
       parent: editorDiv.current,
     });
diff --git a/packages/react/src/components/codemirror/CodeMirrorOutputToolbar.tsx b/packages/react/src/components/codemirror/CodeMirrorOutputToolbar.tsx
index aeec4b99..97878ac4 100644
--- a/packages/react/src/components/codemirror/CodeMirrorOutputToolbar.tsx
+++ b/packages/react/src/components/codemirror/CodeMirrorOutputToolbar.tsx
@@ -107,9 +107,8 @@ export const CodeMirrorOutputToolbar = (props: Props) => {
     () => theme?.colorSchemes.light.colors.severe.muted,
     []
   );
-  const [kernelStatus, setKernelStatus] = useState<KernelMessage.Status>(
-    'unknown'
-  );
+  const [kernelStatus, setKernelStatus] =
+    useState<KernelMessage.Status>('unknown');
   useEffect(() => {
     if (kernel) {
       kernel.ready.then(() => {
diff --git a/packages/react/src/components/console/Console.tsx b/packages/react/src/components/console/Console.tsx
index f532621d..eee61510 100644
--- a/packages/react/src/components/console/Console.tsx
+++ b/packages/react/src/components/console/Console.tsx
@@ -12,11 +12,8 @@ import ConsoleAdapter from './ConsoleAdapter';
 import './Console.css';
 
 export const Console = (options: Console.IConsoleOptions) => {
-  const {
-    defaultKernel,
-    defaultKernelIsLoading,
-    serviceManager,
-  } = useJupyter();
+  const { defaultKernel, defaultKernelIsLoading, serviceManager } =
+    useJupyter();
   const [adapter, setAdapter] = useState<ConsoleAdapter>();
   useEffect(() => {
     if (serviceManager && !defaultKernelIsLoading) {
diff --git a/packages/react/src/components/console/ConsoleAdapter.ts b/packages/react/src/components/console/ConsoleAdapter.ts
index cfb25209..1b3b2dc6 100755
--- a/packages/react/src/components/console/ConsoleAdapter.ts
+++ b/packages/react/src/components/console/ConsoleAdapter.ts
@@ -42,7 +42,6 @@ class ConsoleAdapter {
   }
 
   protected setupConsole(serviceManager: ServiceManager, kernel?: Kernel) {
-
     // Set up a command registry.
     const commands = new CommandRegistry();
     this._panel.node.addEventListener('keydown', event => {
@@ -163,10 +162,9 @@ class ConsoleAdapter {
 
     if (this._code) {
       consolePanel.console.sessionContext.ready.then(() => {
-        this._code!.forEach((line) => consolePanel.console.inject(line));
+        this._code!.forEach(line => consolePanel.console.inject(line));
       });
     }
-
   }
 
   get panel(): BoxPanel {
diff --git a/packages/react/src/components/filemanager/FileManagerJupyterLab.tsx b/packages/react/src/components/filemanager/FileManagerJupyterLab.tsx
index c7993e67..e362411f 100644
--- a/packages/react/src/components/filemanager/FileManagerJupyterLab.tsx
+++ b/packages/react/src/components/filemanager/FileManagerJupyterLab.tsx
@@ -11,9 +11,8 @@ import Lumino from '../lumino/Lumino';
 
 export const FileManagerJupyterLab = () => {
   const { serviceManager } = useJupyter();
-  const [fileManagerAdapter, setFileManagerAdapter] = useState<
-    FileManagerAdapter
-  >();
+  const [fileManagerAdapter, setFileManagerAdapter] =
+    useState<FileManagerAdapter>();
   useEffect(() => {
     if (serviceManager) {
       const fileManagerAdapter = new FileManagerAdapter(serviceManager);
diff --git a/packages/react/src/components/kernel/inspector/widget.tsx b/packages/react/src/components/kernel/inspector/widget.tsx
index f611ef7e..b1ae5870 100644
--- a/packages/react/src/components/kernel/inspector/widget.tsx
+++ b/packages/react/src/components/kernel/inspector/widget.tsx
@@ -64,7 +64,7 @@ function msgNodeRenderer(args: InspectorNodeParams) {
       />
     );
   }
-  const msg = (data as unknown) as KernelMessage.IMessage;
+  const msg = data as unknown as KernelMessage.IMessage;
   return <span key={'node-label'}>{msg.header.msg_id}</span>;
 }
 
diff --git a/packages/react/src/components/kernel/variables/widget.ts b/packages/react/src/components/kernel/variables/widget.ts
index e22fcb2e..5145aee7 100644
--- a/packages/react/src/components/kernel/variables/widget.ts
+++ b/packages/react/src/components/kernel/variables/widget.ts
@@ -59,7 +59,8 @@ type FILTER_TYPES = 'type' | 'name';
  */
 export class VariableInspectorPanel
   extends Widget
-  implements IVariableInspector {
+  implements IVariableInspector
+{
   private _source: IVariableInspector.IInspectable | null = null;
   private _table: WebDataGrid;
   private _filteredTable: HTMLDivElement;
diff --git a/packages/react/src/components/lumino/ReactPortalWidget.ts b/packages/react/src/components/lumino/ReactPortalWidget.ts
index da9122ea..7a74a7d2 100644
--- a/packages/react/src/components/lumino/ReactPortalWidget.ts
+++ b/packages/react/src/components/lumino/ReactPortalWidget.ts
@@ -80,14 +80,14 @@ export abstract class ReactPortalWidget extends Widget {
  * An abstract ReactPortalWidget with a model.
  */
 export abstract class VDomRenderer<
-  T extends VDomRenderer.IModel | null = null
+  T extends VDomRenderer.IModel | null = null,
 > extends ReactPortalWidget {
   /**
    * Create a new VDomRenderer
    */
   constructor(model: T extends null ? void : T) {
     super();
-    this.model = ((model ?? null) as unknown) as T;
+    this.model = (model ?? null) as unknown as T;
   }
   /**
    * A signal emitted when the model changes.
diff --git a/packages/react/src/components/notebook/Notebook.tsx b/packages/react/src/components/notebook/Notebook.tsx
index 9218e08d..6eac368d 100644
--- a/packages/react/src/components/notebook/Notebook.tsx
+++ b/packages/react/src/components/notebook/Notebook.tsx
@@ -67,12 +67,8 @@ export type INotebookProps = {
  * @returns A Notebook React.js component.
  */
 export const Notebook = (props: INotebookProps) => {
-  const {
-    serviceManager,
-    defaultKernel,
-    kernelManager,
-    injectableStore,
-  } = useJupyter();
+  const { serviceManager, defaultKernel, kernelManager, injectableStore } =
+    useJupyter();
   const {
     path,
     kernel: propsKernel,
@@ -83,7 +79,7 @@ export const Notebook = (props: INotebookProps) => {
     nbformat,
     Toolbar,
   } = props;
-  const { lite } = useJupyter()
+  const { lite } = useJupyter();
   const [uid] = useState(props.uid || newUuid());
   const [adapter, setAdapter] = useState<NotebookAdapter>();
   const kernel = propsKernel || defaultKernel;
@@ -111,7 +107,10 @@ export const Notebook = (props: INotebookProps) => {
             const activeCell = adapter.notebookPanel!.content.activeCell;
             if (activeCell) {
               dispatch(
-                notebookActions.activeCellChange({ uid, cellModel: activeCell })
+                notebookActions.activeCellChange({
+                  uid,
+                  cellModel: activeCell,
+                })
               );
             }
             const activeCellChanged$ = asObservable(
diff --git a/packages/react/src/components/notebook/NotebookAdapter.ts b/packages/react/src/components/notebook/NotebookAdapter.ts
index 774cb39b..13b75de5 100755
--- a/packages/react/src/components/notebook/NotebookAdapter.ts
+++ b/packages/react/src/components/notebook/NotebookAdapter.ts
@@ -295,36 +295,37 @@ export class NotebookAdapter {
     }
 
     // These are fixes to have more control on the kernel launch.
-    (this._context.sessionContext as any)._initialize = async (): Promise<
-      boolean
-    > => {
-      const manager = (this._context!.sessionContext as any)
-        .sessionManager as SessionManager;
-      await manager.ready;
-      await manager.refreshRunning();
-      const model = find(manager.running(), model => {
-        return model.kernel?.id === this._kernel.id;
-      });
-      if (model) {
-        try {
-          const session = manager.connectTo({
-            model: {
-              ...model,
-              path: this._path ?? model.path,
-              name: this._path ?? model.name,
-            },
-            kernelConnectionOptions: {
-              handleComms: true,
-            },
-          });
-          (this._context!.sessionContext as any)._handleNewSession(session);
-        } catch (err) {
-          void (this._context!.sessionContext as any)._handleSessionError(err);
-          return Promise.reject(err);
+    (this._context.sessionContext as any)._initialize =
+      async (): Promise<boolean> => {
+        const manager = (this._context!.sessionContext as any)
+          .sessionManager as SessionManager;
+        await manager.ready;
+        await manager.refreshRunning();
+        const model = find(manager.running(), model => {
+          return model.kernel?.id === this._kernel.id;
+        });
+        if (model) {
+          try {
+            const session = manager.connectTo({
+              model: {
+                ...model,
+                path: this._path ?? model.path,
+                name: this._path ?? model.name,
+              },
+              kernelConnectionOptions: {
+                handleComms: true,
+              },
+            });
+            (this._context!.sessionContext as any)._handleNewSession(session);
+          } catch (err) {
+            void (this._context!.sessionContext as any)._handleSessionError(
+              err
+            );
+            return Promise.reject(err);
+          }
         }
-      }
-      return await (this._context!.sessionContext as any)._startIfNecessary();
-    };
+        return await (this._context!.sessionContext as any)._startIfNecessary();
+      };
 
     if (this._ipywidgets === 'lab') {
       const jupyterWidgetRegistry = iPyWidgetsPlugin.activate(
@@ -420,7 +421,7 @@ export class NotebookAdapter {
     this._boxPanel.addWidget(this._notebookPanel);
     BoxPanel.setStretch(this._notebookPanel, 0);
     window.addEventListener('resize', () => {
-      this._notebookPanel?.update()
+      this._notebookPanel?.update();
     });
     const isNbFormat =
       this._path !== undefined && this._path !== '' ? false : true;
@@ -444,9 +445,9 @@ export class NotebookAdapter {
         };
         (this._context as any)._updateContentsModel(model);
         await (this._context as any)._populate();
-        (this._context as Context<
-          INotebookModel
-        >).model.sharedModel.clearUndoHistory();
+        (
+          this._context as Context<INotebookModel>
+        ).model.sharedModel.clearUndoHistory();
       };
     }
     this._context.initialize(isNbFormat).then(() => {
@@ -544,7 +545,7 @@ export class NotebookAdapter {
 
   changeCellType = (cellType: CellType) => {
     //    NotebookActions.changeCellType(this._notebookPanel?.content!, cellType);
-    const notebook = this._notebookPanel?.content!;
+    const notebook = this._notebookPanel!.content!;
     const notebookSharedModel = notebook.model!.sharedModel;
     notebook.widgets.forEach((child, index) => {
       if (!notebook.isSelectedOrActive(child)) {
@@ -560,7 +561,8 @@ export class NotebookAdapter {
             metadata: raw.metadata,
           });
           if (raw.attachments && ['markdown', 'raw'].includes(cellType)) {
-            (newCell as ISharedAttachmentsCell).attachments = raw.attachments as IAttachments;
+            (newCell as ISharedAttachmentsCell).attachments =
+              raw.attachments as IAttachments;
           }
         });
       }
@@ -574,8 +576,8 @@ export class NotebookAdapter {
   };
 
   insertAbove = (source?: string): void => {
-    const notebook = this._notebookPanel?.content!;
-    const model = this._notebookPanel?.context.model!;
+    const notebook = this._notebookPanel!.content!;
+    const model = this._notebookPanel!.context.model!;
     const newIndex = notebook.activeCell ? notebook.activeCellIndex : 0;
     model.sharedModel.insertCell(newIndex, {
       cell_type: notebook.notebookConfig.defaultCell,
@@ -594,8 +596,8 @@ export class NotebookAdapter {
   };
 
   insertBelow = (source?: string): void => {
-    const notebook = this._notebookPanel?.content!;
-    const model = this._notebookPanel?.context.model!;
+    const notebook = this._notebookPanel!.content!;
+    const model = this._notebookPanel!.context.model!;
     const newIndex = notebook.activeCell ? notebook.activeCellIndex + 1 : 0;
     model.sharedModel.insertCell(newIndex, {
       cell_type: notebook.notebookConfig.defaultCell,
diff --git a/packages/react/src/components/notebook/NotebookCommands.ts b/packages/react/src/components/notebook/NotebookCommands.ts
index adfa1783..d85eb57c 100644
--- a/packages/react/src/components/notebook/NotebookCommands.ts
+++ b/packages/react/src/components/notebook/NotebookCommands.ts
@@ -322,7 +322,7 @@ export const NotebookCommands = (
       command: cmdIds.invokeNotebook,
     },
     {
-      selector: `.jp-mod-completer-active`,
+      selector: '.jp-mod-completer-active',
       keys: ['Enter'],
       command: cmdIds.selectNotebook,
     },
diff --git a/packages/react/src/components/notebook/cell/metadata/CellMetadataEditor.tsx b/packages/react/src/components/notebook/cell/metadata/CellMetadataEditor.tsx
index 05cdc870..829e56d4 100644
--- a/packages/react/src/components/notebook/cell/metadata/CellMetadataEditor.tsx
+++ b/packages/react/src/components/notebook/cell/metadata/CellMetadataEditor.tsx
@@ -34,7 +34,7 @@ export const CellMetadataEditor = (props: Props) => {
     });
   };
   const handlePointsChange = (cell: Cell<ICellModel>, points: string) => {
-    var points_number: number = +points;
+    const points_number: number = +points;
     if (!isNaN(points_number)) {
       const nbgrader = cell.model.getMetadata('nbgrader') as any;
       cell.model.setMetadata('nbgrader', {
diff --git a/packages/react/src/components/notebook/cell/metadata/NbGraderCells.tsx b/packages/react/src/components/notebook/cell/metadata/NbGraderCells.tsx
index 3ad04547..c7f7ed14 100644
--- a/packages/react/src/components/notebook/cell/metadata/NbGraderCells.tsx
+++ b/packages/react/src/components/notebook/cell/metadata/NbGraderCells.tsx
@@ -6,7 +6,7 @@
 
 import { Cell, ICellModel } from '@jupyterlab/cells';
 /*
-// Autograded answer (only for code cells) { grade: false, solution: true, locked: false  }
+// Autograded answer (only for code cells) { grade: false, solution: true, locked: false  }
 {
   "nbgrader": {
     "grade_id": "squares",
@@ -16,7 +16,7 @@ import { Cell, ICellModel } from '@jupyterlab/cells';
     "locked": false
   }
 }
-// Autograded test (only for code cells) { grade: true, solution: false, locked: false, points: ... }
+// Autograded test (only for code cells) { grade: true, solution: false, locked: false, points: ... }
 {
   "nbgrader": {
     "grade_id": "correct_squares",
@@ -27,7 +27,7 @@ import { Cell, ICellModel } from '@jupyterlab/cells';
     "points": 1
   }
 }
-// Manually graded task { grade: false, solution: false, locked: true, task: true, points: ... }
+// Manually graded task { grade: false, solution: false, locked: true, task: true, points: ... }
 {
   "nbgrader": {
     "grade_id": "part-a",
@@ -39,7 +39,7 @@ import { Cell, ICellModel } from '@jupyterlab/cells';
     "points": 0
   }
 }
-// Manually graded answer { grade: true, solution: true, locked: false, points: ... }
+// Manually graded answer { grade: true, solution: true, locked: false, points: ... }
 {
   "nbgrader": {
     "grade_id": "sum_of_squares_equation",
@@ -50,7 +50,7 @@ import { Cell, ICellModel } from '@jupyterlab/cells';
     "points": 1
   }
 }
-// Readonly { grade: false, solution: false, solution: false, locked: true, task: false }
+// Readonly { grade: false, solution: false, solution: false, locked: true, task: false }
 {
   "nbgrader": {
     "grade_id": "squares",
@@ -80,23 +80,23 @@ export const getNbGraderType = (cell: Cell<ICellModel>) => {
   const solution = nbgrader.solution;
   const locked = nbgrader.locked;
   const task = nbgrader.task;
-  // Autograded answer (only for code cells) { grade: false, solution: true, locked: false  }
+  // Autograded answer (only for code cells) { grade: false, solution: true, locked: false  }
   if (!grade && solution && !locked) {
     return NbGraderType.AutogradedAnswer;
   }
-  // Autograded test (only for code cells) { grade: true, solution: false, locked: false, points: ... }
+  // Autograded test (only for code cells) { grade: true, solution: false, locked: false, points: ... }
   if (grade && !solution && !locked) {
     return NbGraderType.AutogradedTest;
   }
-  // Manually graded task { grade: false, solution: false, locked: true, task: true, points: ... }
+  // Manually graded task { grade: false, solution: false, locked: true, task: true, points: ... }
   if (!grade && !solution && locked && task) {
     return NbGraderType.ManuallyGradedTask;
   }
-  // Manually graded answer { grade: true, solution: true, locked: false, points: ... }
+  // Manually graded answer { grade: true, solution: true, locked: false, points: ... }
   if (grade && solution && !locked) {
     return NbGraderType.ManuallyGradedAnswer;
   }
-  // Readonly { grade: false, solution: false, solution: false, locked: true, task: false }
+  // Readonly { grade: false, solution: false, solution: false, locked: true, task: false }
   if (!grade && !solution && locked && !task) {
     return NbGraderType.ReadonlyGraded;
   }
diff --git a/packages/react/src/components/notebook/cell/prompt/Countdown.tsx b/packages/react/src/components/notebook/cell/prompt/Countdown.tsx
index a550bd35..d0cf5724 100644
--- a/packages/react/src/components/notebook/cell/prompt/Countdown.tsx
+++ b/packages/react/src/components/notebook/cell/prompt/Countdown.tsx
@@ -8,7 +8,7 @@ import { useState, useEffect, useRef } from 'react';
 
 export const Countdown = (props: { count: number }) => {
   const [count, setCount] = useState(props.count);
-  let intervalRef = useRef<number>();
+  const intervalRef = useRef<number>();
   const decreaseNum = () => setCount(prev => prev - 1);
   useEffect(() => {
     setCount(props.count);
diff --git a/packages/react/src/components/notebook/cell/prompt/CountdownOutputPrompt.tsx b/packages/react/src/components/notebook/cell/prompt/CountdownOutputPrompt.tsx
index 419aeace..850527cd 100644
--- a/packages/react/src/components/notebook/cell/prompt/CountdownOutputPrompt.tsx
+++ b/packages/react/src/components/notebook/cell/prompt/CountdownOutputPrompt.tsx
@@ -13,7 +13,8 @@ const OUTPUT_PROMPT_CLASS = 'jp-OutputPrompt';
 
 export class CountdownOutputPrompt
   extends ReactWidget
-  implements IOutputPrompt {
+  implements IOutputPrompt
+{
   private _executionCount: ExecutionCount = null;
 
   private state = {
diff --git a/packages/react/src/components/notebook/cell/sidebar/CellSidebarWidget.tsx b/packages/react/src/components/notebook/cell/sidebar/CellSidebarWidget.tsx
index 543eb3cf..50b6655c 100644
--- a/packages/react/src/components/notebook/cell/sidebar/CellSidebarWidget.tsx
+++ b/packages/react/src/components/notebook/cell/sidebar/CellSidebarWidget.tsx
@@ -24,7 +24,8 @@ export type CellSidebarProps = {
 
 export class CellSidebarWidget
   extends ReactPortalWidget
-  implements ICellHeader {
+  implements ICellHeader
+{
   private readonly commands: CommandRegistry;
   constructor(
     CellSidebar: (props: CellSidebarProps) => JSX.Element,
diff --git a/packages/react/src/components/notebook/marked/marked.ts b/packages/react/src/components/notebook/marked/marked.ts
index fbd669cf..8b94d096 100644
--- a/packages/react/src/components/notebook/marked/marked.ts
+++ b/packages/react/src/components/notebook/marked/marked.ts
@@ -38,7 +38,7 @@ namespace Private {
       gfm: true,
       sanitize: false,
       // breaks: true; We can't use GFM breaks as it causes problems with tables
-      langPrefix: `language-`,
+      langPrefix: 'language-',
       highlight: (code, lang, callback) => {
         const cb = (err: Error | null, code: string) => {
           if (callback) {
diff --git a/packages/react/src/components/output/Output.tsx b/packages/react/src/components/output/Output.tsx
index e2af12ec..cc001b1a 100644
--- a/packages/react/src/components/output/Output.tsx
+++ b/packages/react/src/components/output/Output.tsx
@@ -63,9 +63,8 @@ export const Output = (props: IOutputProps) => {
   } = props;
   const dispatch = useDispatch();
   const [id, setId] = useState<string | undefined>(sourceId);
-  const [kernelStatus, setKernelStatus] = useState<KernelMessage.Status>(
-    'unknown'
-  );
+  const [kernelStatus, setKernelStatus] =
+    useState<KernelMessage.Status>('unknown');
   const [outputs, setOutputs] = useState<IOutput[] | undefined>(props.outputs);
   const [adapter, setAdapter] = useState<OutputAdapter>();
   useMemo(() => {
diff --git a/packages/react/src/components/output/OutputAdapter.ts b/packages/react/src/components/output/OutputAdapter.ts
index cd7bc330..c28a88fd 100755
--- a/packages/react/src/components/output/OutputAdapter.ts
+++ b/packages/react/src/components/output/OutputAdapter.ts
@@ -75,8 +75,9 @@ export class OutputAdapter {
       if (data) {
         const isPlotly = data['application/vnd.plotly.v1+json'];
         if (isPlotly) {
-          let script = this._outputArea.node.children[0].children[1].children[0]
-            .children[1].innerHTML;
+          let script =
+            this._outputArea.node.children[0].children[1].children[0]
+              .children[1].innerHTML;
           script = script.replaceAll('\n,', '\n');
           eval(script);
         }
diff --git a/packages/react/src/components/output/OutputRenderer.tsx b/packages/react/src/components/output/OutputRenderer.tsx
index 63099ce8..9cd3cbe0 100644
--- a/packages/react/src/components/output/OutputRenderer.tsx
+++ b/packages/react/src/components/output/OutputRenderer.tsx
@@ -77,7 +77,9 @@ export const OutputRenderer = (props: Props) => {
         plain = t ? 'true' : 'false';
       } else if (Array.isArray(t)) {
         plain = (t as string[]).join('\n');
-      } else plain = t?.toString();
+      } else {
+        plain = t?.toString();
+      }
       break;
     }
     case 'display_data': {
@@ -99,7 +101,9 @@ export const OutputRenderer = (props: Props) => {
             plain = text_plain;
           } else if (Array.isArray(text_plain)) {
             plain = text_plain.join('\n');
-          } else plain = text_plain.toString();
+          } else {
+            plain = text_plain.toString();
+          }
         }
         const text_html = data['text/html'];
         if (text_html) {
diff --git a/packages/react/src/components/output/ipywidgets/IPyWidgetsAttached.tsx b/packages/react/src/components/output/ipywidgets/IPyWidgetsAttached.tsx
index 7d95e0f5..9c66b3c7 100644
--- a/packages/react/src/components/output/ipywidgets/IPyWidgetsAttached.tsx
+++ b/packages/react/src/components/output/ipywidgets/IPyWidgetsAttached.tsx
@@ -21,7 +21,7 @@ const IPyWidgetsAttached = (props: Props) => {
     <div
       ref={ref => {
         if (ref) {
-          var manager = new IPyWidgetsViewManager(ref);
+          const manager = new IPyWidgetsViewManager(ref);
           manager
             .set_state(state)
             .then((models: any) =>
diff --git a/packages/react/src/components/output/ipywidgets/IPyWidgetsViewManager.ts b/packages/react/src/components/output/ipywidgets/IPyWidgetsViewManager.ts
index a8d2a2ee..4198fe2e 100644
--- a/packages/react/src/components/output/ipywidgets/IPyWidgetsViewManager.ts
+++ b/packages/react/src/components/output/ipywidgets/IPyWidgetsViewManager.ts
@@ -21,14 +21,14 @@ export class IPyWidgetsViewManager extends ManagerBase {
     moduleName: string,
     moduleVersion: string
   ) {
-    return new Promise(function (resolve, reject) {
+    return new Promise((resolve, reject) => {
       if (moduleName === '@jupyter-widgets/controls') {
         resolve(controls);
       } else if (moduleName === '@jupyter-widgets/base') {
         resolve(base);
       } else {
-        var fallback = function (err: any) {
-          let failedId = err.requireModules && err.requireModules[0];
+        const fallback = function (err: any) {
+          const failedId = err.requireModules && err.requireModules[0];
           if (failedId) {
             console.log(
               `Falling back to jsDelivr for ${moduleName}@${moduleVersion}`
@@ -46,7 +46,7 @@ export class IPyWidgetsViewManager extends ManagerBase {
         };
         (window as any).require([`${moduleName}.js`], resolve, fallback);
       }
-    }).then(function (module: any) {
+    }).then((module: any) => {
       if (module[className]) {
         return module[className];
       } else {
@@ -57,8 +57,9 @@ export class IPyWidgetsViewManager extends ManagerBase {
     });
   }
   async display_view(view: any) {
-    var that = this;
-    return Promise.resolve(view).then(function (view) {
+    // eslint-disable-next-line @typescript-eslint/no-this-alias
+    const that = this;
+    return Promise.resolve(view).then(view => {
       Widget.attach(view.luminoWidget, that.el);
       return view;
     });
diff --git a/packages/react/src/components/viewer/output/OutputAdapter.ts b/packages/react/src/components/viewer/output/OutputAdapter.ts
index 8a61dad4..3f3dd5a0 100755
--- a/packages/react/src/components/viewer/output/OutputAdapter.ts
+++ b/packages/react/src/components/viewer/output/OutputAdapter.ts
@@ -40,8 +40,9 @@ export class OutputAdapter {
       const data = outputs[0].data as any;
       const isPlotly = data['application/vnd.plotly.v1+json'];
       if (isPlotly) {
-        let script = this._outputArea.node.children[0].children[1].children[0]
-          .children[1].innerHTML;
+        let script =
+          this._outputArea.node.children[0].children[1].children[0].children[1]
+            .innerHTML;
         script = script.replaceAll('\n,', '\n');
         eval(script);
       }
diff --git a/packages/react/src/examples/CellLite.tsx b/packages/react/src/examples/CellLite.tsx
index b5d3b8cd..b4b9df58 100644
--- a/packages/react/src/examples/CellLite.tsx
+++ b/packages/react/src/examples/CellLite.tsx
@@ -16,7 +16,9 @@ const root = createRoot(div);
 root.render(
   <Jupyter lite={true}>
     <Box as="h1">A Jupyter Cell with a Lite Kernel</Box>
-    <Cell source={`print('👋 Hello Jupyter UI Lite')
-get_ipython()`}/>
+    <Cell
+      source={`print('👋 Hello Jupyter UI Lite')
+get_ipython()`}
+    />
   </Jupyter>
 );
diff --git a/packages/react/src/examples/Console.tsx b/packages/react/src/examples/Console.tsx
index f3fff5ef..967b04c9 100644
--- a/packages/react/src/examples/Console.tsx
+++ b/packages/react/src/examples/Console.tsx
@@ -16,12 +16,6 @@ const root = createRoot(div);
 root.render(
   <Jupyter>
     <Box as="h1">A Jupyter Console</Box>
-    <Console
-      code={
-        [
-          "print('👋 Hello Jupyter Console')"
-        ]
-      }
-    />
+    <Console code={["print('👋 Hello Jupyter Console')"]} />
   </Jupyter>
 );
diff --git a/packages/react/src/examples/ConsoleLite.tsx b/packages/react/src/examples/ConsoleLite.tsx
index 4f45e627..979872da 100644
--- a/packages/react/src/examples/ConsoleLite.tsx
+++ b/packages/react/src/examples/ConsoleLite.tsx
@@ -17,14 +17,11 @@ root.render(
   <Jupyter lite={true}>
     <Box as="h1">A Jupyter Console with a Lite Kernel</Box>
     <Console
-      code={
-        [
-          "import piplite",
-          "await piplite.install('numpy')",
-          "print('👋 Hello Jupyter Console')"
-        ]
-      }
+      code={[
+        'import piplite',
+        "await piplite.install('numpy')",
+        "print('👋 Hello Jupyter Console')",
+      ]}
     />
-
   </Jupyter>
 );
diff --git a/packages/react/src/examples/JupyterLabHeadlessApp.tsx b/packages/react/src/examples/JupyterLabHeadlessApp.tsx
index e32ff8d7..868a759e 100644
--- a/packages/react/src/examples/JupyterLabHeadlessApp.tsx
+++ b/packages/react/src/examples/JupyterLabHeadlessApp.tsx
@@ -37,9 +37,8 @@ const PATH_INDEX = 1;
 const JupyterLabHeadlessAppExample = () => {
   const [notebookBoxPanel, setNotebookBoxPanel] = useState<BoxPanel>();
   const [theme, setTheme] = useState<ColorMode>('light');
-  const [jupyterLabAdapter, setJupyterlabAdapter] = useState<
-    JupyterLabAppAdapter
-  >();
+  const [jupyterLabAdapter, setJupyterlabAdapter] =
+    useState<JupyterLabAppAdapter>();
   const { setColorMode } = useTheme();
   const [isDark, setDark] = useState(false);
   const onSwitchClick = async () => {
diff --git a/packages/react/src/examples/KernelExecutor.tsx b/packages/react/src/examples/KernelExecutor.tsx
index e7a2a0aa..25aa0bc0 100644
--- a/packages/react/src/examples/KernelExecutor.tsx
+++ b/packages/react/src/examples/KernelExecutor.tsx
@@ -27,9 +27,8 @@ print("🔁 I am done with looping!")`;
 const KernelExecutorView = () => {
   const { defaultKernel } = useJupyter();
   const [outputAreaModel, setOutputAreaModel] = useState<IOutputAreaModel>();
-  const [finalOutputAreaModel, setFinalOutputAreaModel] = useState<
-    IOutputAreaModel
-  >();
+  const [finalOutputAreaModel, setFinalOutputAreaModel] =
+    useState<IOutputAreaModel>();
   const [done, setDone] = useState(false);
   useEffect(() => {
     if (defaultKernel?.connection) {
diff --git a/packages/react/src/examples/NotebookInit.tsx b/packages/react/src/examples/NotebookInit.tsx
index f6609322..96e6120e 100644
--- a/packages/react/src/examples/NotebookInit.tsx
+++ b/packages/react/src/examples/NotebookInit.tsx
@@ -79,7 +79,7 @@ const NotebookInit: React.FC = () => {
             notebookActions.insertAbove.started({
               uid: NOTEBOOK_ID,
               cellType: 'code',
-              source: `print("Hello 🪐 ⚛️ Jupyter React")`,
+              source: 'print("Hello 🪐 ⚛️ Jupyter React")',
             })
           );
         }
diff --git a/packages/react/src/examples/RunningSessions.tsx b/packages/react/src/examples/RunningSessions.tsx
index ab52d768..a7f48d32 100644
--- a/packages/react/src/examples/RunningSessions.tsx
+++ b/packages/react/src/examples/RunningSessions.tsx
@@ -28,9 +28,8 @@ import * as runningExtension from '@jupyterlab/running-extension';
 const RunningSessionsExample = () => {
   const [runningSessions, setRunningSessions] = useState<RunningSessions>();
   const [theme, setTheme] = useState<ColorMode>('light');
-  const [jupyterLabAdapter, setJupyterlabAdapter] = useState<
-    JupyterLabAppAdapter
-  >();
+  const [jupyterLabAdapter, setJupyterlabAdapter] =
+    useState<JupyterLabAppAdapter>();
   const { setColorMode } = useTheme();
   const [isDark, setDark] = useState(false);
   const onSwitchClick = async () => {
diff --git a/packages/react/src/examples/Viewer.tsx b/packages/react/src/examples/Viewer.tsx
index 4eaf6e8a..a3cdebdc 100644
--- a/packages/react/src/examples/Viewer.tsx
+++ b/packages/react/src/examples/Viewer.tsx
@@ -27,49 +27,41 @@ type NotebookExample = {
 const visualisationExamples: NotebookExample[] = [
   {
     title: 'Plotly Daily Stocks',
-    url:
-      'https://raw.githubusercontent.com/datalayer-examples/notebooks/main/daily-stock.ipynb',
+    url: 'https://raw.githubusercontent.com/datalayer-examples/notebooks/main/daily-stock.ipynb',
   },
   {
     title: 'Matplotlib',
-    url:
-      'https://raw.githubusercontent.com/anissa111/matplotlib-tutorial/main/notebooks/01-basic-matplotlib-tutorial.ipynb',
+    url: 'https://raw.githubusercontent.com/anissa111/matplotlib-tutorial/main/notebooks/01-basic-matplotlib-tutorial.ipynb',
   },
   {
     title: 'Bicycle Control',
-    url:
-      'https://raw.githubusercontent.com/plotly/IPython-plotly/master/notebooks/bicycle_control/bicycle_control.ipynb',
+    url: 'https://raw.githubusercontent.com/plotly/IPython-plotly/master/notebooks/bicycle_control/bicycle_control.ipynb',
   },
   {
     title: 'IPyWidgets Example',
-    url:
-      ' https://raw.githubusercontent.com/jupyter-widgets/ipywidgets/main/docs/source/examples/Widget%20Basics.ipynb',
+    url: ' https://raw.githubusercontent.com/jupyter-widgets/ipywidgets/main/docs/source/examples/Widget%20Basics.ipynb',
   },
 ];
 
 const dataScienceExamples: NotebookExample[] = [
   {
     title: 'Fair Experiment',
-    url:
-      'https://raw.githubusercontent.com/datalayer-courses/foundations-of-data-science-with-python/main/04-probability1/fair-experiments.ipynb',
+    url: 'https://raw.githubusercontent.com/datalayer-courses/foundations-of-data-science-with-python/main/04-probability1/fair-experiments.ipynb',
   },
   {
     title: 'Text Vectorization',
-    url:
-      'https://raw.githubusercontent.com/datalayer-courses/python-text-mining-intro/main/4-text-vectorization.ipynb',
+    url: 'https://raw.githubusercontent.com/datalayer-courses/python-text-mining-intro/main/4-text-vectorization.ipynb',
   },
   {
     title: 'Survival Analysis',
-    url:
-      'https://raw.githubusercontent.com/plotly/IPython-plotly/master/notebooks/survival_analysis/survival_analysis.ipynb',
+    url: 'https://raw.githubusercontent.com/plotly/IPython-plotly/master/notebooks/survival_analysis/survival_analysis.ipynb',
   },
 ];
 
 const astronomyExamples: NotebookExample[] = [
   {
     title: 'Center of Mass',
-    url:
-      'https://raw.githubusercontent.com/JuanCab/AstroInteractives/master/Interactives/Center_of_Mass.ipynb',
+    url: 'https://raw.githubusercontent.com/JuanCab/AstroInteractives/master/Interactives/Center_of_Mass.ipynb',
   },
   /*
   {
diff --git a/packages/react/src/examples/lumino/LuminoWidget.ts b/packages/react/src/examples/lumino/LuminoWidget.ts
index 0e62d6c4..56d73b2d 100755
--- a/packages/react/src/examples/lumino/LuminoWidget.ts
+++ b/packages/react/src/examples/lumino/LuminoWidget.ts
@@ -23,9 +23,9 @@ class LuminoWidget extends Widget {
   }
 
   static createNode(): HTMLElement {
-    let node = document.createElement('div');
-    let content = document.createElement('div');
-    let input = document.createElement('input');
+    const node = document.createElement('div');
+    const content = document.createElement('div');
+    const input = document.createElement('input');
     input.placeholder = 'Placeholder...';
     content.appendChild(input);
     node.appendChild(content);
diff --git a/packages/react/src/examples/toolbars/NotebookToolbar.tsx b/packages/react/src/examples/toolbars/NotebookToolbar.tsx
index 70e9bf8e..34903803 100644
--- a/packages/react/src/examples/toolbars/NotebookToolbar.tsx
+++ b/packages/react/src/examples/toolbars/NotebookToolbar.tsx
@@ -136,48 +136,49 @@ export const NotebookToolbar = (props: { notebookId: string }) => {
           title="Insert cell"
           onClick={e => {
             e.preventDefault();
-            if (type === 'raw')
+            if (type === 'raw') {
               dispatch(
                 notebookActions.insertBelow.started({
                   uid: notebookId,
                   cellType: 'raw',
                 })
               );
-            else if (type === 'code')
+            } else if (type === 'code') {
               dispatch(
                 notebookActions.insertBelow.started({
                   uid: notebookId,
                   cellType: 'code',
                 })
               );
-            else if (type === 'markdown')
+            } else if (type === 'markdown') {
               dispatch(
                 notebookActions.insertBelow.started({
                   uid: notebookId,
                   cellType: 'markdown',
                 })
               );
+            }
           }}
           style={{ color: 'grey' }}
           icon={PlusIcon}
         />
         <ButtonGroup>
           <Button
-            variant={type == 'code' ? 'primary' : 'invisible'}
+            variant={type === 'code' ? 'primary' : 'invisible'}
             onClick={() => handleChangeCellType('code')}
             size="small"
           >
             Code
           </Button>
           <Button
-            variant={type == 'markdown' ? 'primary' : 'invisible'}
+            variant={type === 'markdown' ? 'primary' : 'invisible'}
             onClick={() => handleChangeCellType('markdown')}
             size="small"
           >
             Markdown
           </Button>
           <Button
-            variant={type == 'raw' ? 'primary' : 'invisible'}
+            variant={type === 'raw' ? 'primary' : 'invisible'}
             onClick={() => handleChangeCellType('raw')}
             size="small"
           >
diff --git a/packages/react/src/examples/toolbars/NotebookToolbarAutoSave.tsx b/packages/react/src/examples/toolbars/NotebookToolbarAutoSave.tsx
index d49c2bfd..4e7d6c14 100644
--- a/packages/react/src/examples/toolbars/NotebookToolbarAutoSave.tsx
+++ b/packages/react/src/examples/toolbars/NotebookToolbarAutoSave.tsx
@@ -165,21 +165,21 @@ export const NotebookToolbarAutoSave = (props: { notebookId: string }) => {
         />
         <ButtonGroup>
           <Button
-            variant={addType == 'code' ? 'primary' : 'invisible'}
+            variant={addType === 'code' ? 'primary' : 'invisible'}
             onClick={() => handleChangeCellType('code')}
             size="small"
           >
             Code
           </Button>
           <Button
-            variant={addType == 'markdown' ? 'primary' : 'default'}
+            variant={addType === 'markdown' ? 'primary' : 'default'}
             onClick={() => handleChangeCellType('markdown')}
             size="small"
           >
             Markdown
           </Button>
           <Button
-            variant={addType == 'raw' ? 'primary' : 'invisible'}
+            variant={addType === 'raw' ? 'primary' : 'invisible'}
             onClick={() => handleChangeCellType('raw')}
             size="small"
           >
diff --git a/packages/react/src/jupyter/JupyterContext.tsx b/packages/react/src/jupyter/JupyterContext.tsx
index 1660af0a..08b9857a 100644
--- a/packages/react/src/jupyter/JupyterContext.tsx
+++ b/packages/react/src/jupyter/JupyterContext.tsx
@@ -18,9 +18,9 @@ import { getJupyterServerHttpUrl, getJupyterToken } from './JupyterConfig';
 import { requestAPI } from './JupyterHandlers';
 import Kernel from './kernel/Kernel';
 
-export type Lite = 
+export type Lite =
   | boolean
-  | Promise<{ default: JupyterLiteServerPlugin<any>[] }>
+  | Promise<{ default: JupyterLiteServerPlugin<any>[] }>;
 
 /**
  * The type for the Jupyter context.
@@ -98,8 +98,9 @@ export const JupyterContext = createContext<JupyterContextType | undefined>(
 
 export const useJupyter = (): JupyterContextType => {
   const context = useContext(JupyterContext);
-  if (!context)
+  if (!context) {
     throw new Error('useContext must be inside a provider with a value.');
+  }
   return context;
 };
 
diff --git a/packages/react/src/jupyter/ipywidgets/cache/semvercache.ts b/packages/react/src/jupyter/ipywidgets/cache/semvercache.ts
index 27b45fc3..c6e51a90 100644
--- a/packages/react/src/jupyter/ipywidgets/cache/semvercache.ts
+++ b/packages/react/src/jupyter/ipywidgets/cache/semvercache.ts
@@ -35,13 +35,16 @@ export class SemVerCache<T> {
     }
   }
 
-  getAllVersions(key: string): Object | undefined {
+  getAllVersions(key: string):
+    | {
+        [version: string]: any;
+      }
+    | undefined {
     if (key in this._cache) {
       return this._cache[key];
     }
   }
 
-  private _cache: { [key: string]: { [version: string]: T } } = Object.create(
-    null
-  );
+  private _cache: { [key: string]: { [version: string]: T } } =
+    Object.create(null);
 }
diff --git a/packages/react/src/jupyter/ipywidgets/classic/IPyWidgetsClassicManager.ts b/packages/react/src/jupyter/ipywidgets/classic/IPyWidgetsClassicManager.ts
index 14f3cebc..80ed6234 100644
--- a/packages/react/src/jupyter/ipywidgets/classic/IPyWidgetsClassicManager.ts
+++ b/packages/react/src/jupyter/ipywidgets/classic/IPyWidgetsClassicManager.ts
@@ -123,7 +123,7 @@ export class IPyWidgetsClassicManager extends HTMLManager {
   ): Promise<void> {
     return Promise.resolve(view).then(view => {
       Widget.attach(view.luminoWidget, el);
-      view.on('remove', function () {
+      view.on('remove', () => {
         console.log('The IPyWidgets view is removed', view);
       });
       //      return view;
@@ -212,7 +212,7 @@ export class IPyWidgetsClassicManager extends HTMLManager {
     return Promise.resolve(new shims.services.Comm(comm!));
   }
 
-  public _get_comm_info(): Promise<{}> {
+  public _get_comm_info(): Promise<any> {
     return this._kernelConnection!.requestCommInfo({
       target_name: this.comm_target_name,
     }).then((reply: any) => reply.content.comms);
diff --git a/packages/react/src/jupyter/ipywidgets/lab/manager.ts b/packages/react/src/jupyter/ipywidgets/lab/manager.ts
index f5f976ec..0a128d81 100644
--- a/packages/react/src/jupyter/ipywidgets/lab/manager.ts
+++ b/packages/react/src/jupyter/ipywidgets/lab/manager.ts
@@ -49,7 +49,8 @@ export const WIDGET_STATE_MIMETYPE =
  */
 export abstract class BaseWidgetManager
   extends ManagerBase
-  implements IDisposable {
+  implements IDisposable
+{
   constructor(rendermime: IRenderMimeRegistry) {
     super();
     this._rendermime = rendermime;
diff --git a/packages/react/src/jupyter/ipywidgets/lab/renderer.ts b/packages/react/src/jupyter/ipywidgets/lab/renderer.ts
index d8feea50..9325b5df 100644
--- a/packages/react/src/jupyter/ipywidgets/lab/renderer.ts
+++ b/packages/react/src/jupyter/ipywidgets/lab/renderer.ts
@@ -19,7 +19,8 @@ import { DOMWidgetModel } from '@jupyter-widgets/base';
  */
 export class WidgetRenderer
   extends Panel
-  implements IRenderMime.IRenderer, IDisposable {
+  implements IRenderMime.IRenderer, IDisposable
+{
   constructor(
     options: IRenderMime.IRendererOptions,
     manager?: BaseWidgetManager
diff --git a/packages/react/src/jupyter/ipywidgets/plotly/Figure.ts b/packages/react/src/jupyter/ipywidgets/plotly/Figure.ts
index 69a1cbe6..111e632e 100644
--- a/packages/react/src/jupyter/ipywidgets/plotly/Figure.ts
+++ b/packages/react/src/jupyter/ipywidgets/plotly/Figure.ts
@@ -4,6 +4,12 @@
  * MIT License
  */
 
+/* eslint-disable @typescript-eslint/ban-ts-comment */
+/* eslint-disable @typescript-eslint/no-this-alias */
+/* eslint-disable prefer-rest-params */
+/* eslint-disable no-var */
+/* eslint-disable no-prototype-builtins */
+
 import {
   DOMWidgetModel,
   DOMWidgetView,
@@ -13,7 +19,7 @@ import _ from 'lodash';
 import Plotly from 'plotly.js';
 import { MODULE_NAME, MODULE_VERSION } from './Version';
 
-// @ts-ignore
+// @ts-expect-error unknown global PlotlyConfig
 window.PlotlyConfig = { MathJaxConfig: 'local' };
 const semver_range = '^' + MODULE_VERSION;
 
@@ -542,7 +548,7 @@ export class FigureModel extends DOMWidgetModel {
    */
   _normalize_trace_indexes(trace_indexes?: null | number | number[]): number[] {
     if (trace_indexes === null || trace_indexes === undefined) {
-      var numTraces = this.get('_data').length;
+      const numTraces = this.get('_data').length;
       trace_indexes = _.range(numTraces);
     }
     if (!Array.isArray(trace_indexes)) {
@@ -572,12 +578,12 @@ export class FigureModel extends DOMWidgetModel {
   do_addTraces() {
     // add trace to plot
     /** @type {Py2JsAddTracesMsg} */
-    var msgData: Py2JsAddTracesMsg = this.get('_py2js_addTraces');
+    const msgData: Py2JsAddTracesMsg = this.get('_py2js_addTraces');
 
     if (msgData !== null) {
-      var currentTraces = this.get('_data');
-      var newTraces = msgData.trace_data;
-      _.forEach(newTraces, function (newTrace) {
+      const currentTraces = this.get('_data');
+      const newTraces = msgData.trace_data;
+      _.forEach(newTraces, newTrace => {
         currentTraces.push(newTrace);
       });
     }
@@ -590,18 +596,18 @@ export class FigureModel extends DOMWidgetModel {
     // remove traces from plot
 
     /** @type {Py2JsDeleteTracesMsg} */
-    var msgData: Py2JsDeleteTracesMsg = this.get('_py2js_deleteTraces');
+    const msgData: Py2JsDeleteTracesMsg = this.get('_py2js_deleteTraces');
 
     if (msgData !== null) {
-      var delete_inds = msgData.delete_inds;
-      var tracesData = this.get('_data');
+      const delete_inds = msgData.delete_inds;
+      const tracesData = this.get('_data');
 
       // Remove del inds in reverse order so indexes remain valid
       // throughout loop
       delete_inds
         .slice()
         .reverse()
-        .forEach(function (del_ind) {
+        .forEach(del_ind => {
           tracesData.splice(del_ind, 1);
         });
     }
@@ -612,12 +618,12 @@ export class FigureModel extends DOMWidgetModel {
    */
   do_moveTraces() {
     /** @type {Py2JsMoveTracesMsg} */
-    var msgData: Py2JsMoveTracesMsg = this.get('_py2js_moveTraces');
+    const msgData: Py2JsMoveTracesMsg = this.get('_py2js_moveTraces');
 
     if (msgData !== null) {
-      var tracesData = this.get('_data');
-      var currentInds = msgData.current_trace_inds;
-      var newInds = msgData.new_trace_inds;
+      const tracesData = this.get('_data');
+      const currentInds = msgData.current_trace_inds;
+      const newInds = msgData.new_trace_inds;
 
       performMoveTracesLike(tracesData, currentInds, newInds);
     }
@@ -628,10 +634,12 @@ export class FigureModel extends DOMWidgetModel {
    */
   do_restyle() {
     /** @type {Py2JsRestyleMsg} */
-    var msgData: Py2JsRestyleMsg = this.get('_py2js_restyle');
+    const msgData: Py2JsRestyleMsg = this.get('_py2js_restyle');
     if (msgData !== null) {
-      var restyleData = msgData.restyle_data;
-      var restyleTraces = this._normalize_trace_indexes(msgData.restyle_traces);
+      const restyleData = msgData.restyle_data;
+      const restyleTraces = this._normalize_trace_indexes(
+        msgData.restyle_traces
+      );
       performRestyleLike(this.get('_data'), restyleData, restyleTraces);
     }
   }
@@ -641,7 +649,7 @@ export class FigureModel extends DOMWidgetModel {
    */
   do_relayout() {
     /** @type {Py2JsRelayoutMsg} */
-    var msgData: Py2JsRelayoutMsg = this.get('_py2js_relayout');
+    const msgData: Py2JsRelayoutMsg = this.get('_py2js_relayout');
 
     if (msgData !== null) {
       performRelayoutLike(this.get('_layout'), msgData.relayout_data);
@@ -653,12 +661,12 @@ export class FigureModel extends DOMWidgetModel {
    */
   do_update() {
     /** @type {Py2JsUpdateMsg} */
-    var msgData: Py2JsUpdateMsg = this.get('_py2js_update');
+    const msgData: Py2JsUpdateMsg = this.get('_py2js_update');
 
     if (msgData !== null) {
-      var style = msgData.style_data;
-      var layout = msgData.layout_data;
-      var styleTraces = this._normalize_trace_indexes(msgData.style_traces);
+      const style = msgData.style_data;
+      const layout = msgData.layout_data;
+      const styleTraces = this._normalize_trace_indexes(msgData.style_traces);
       performRestyleLike(this.get('_data'), style, styleTraces);
       performRelayoutLike(this.get('_layout'), layout);
     }
@@ -669,16 +677,16 @@ export class FigureModel extends DOMWidgetModel {
    */
   do_animate() {
     /** @type {Py2JsAnimateMsg} */
-    var msgData: Py2JsAnimateMsg = this.get('_py2js_animate');
+    const msgData: Py2JsAnimateMsg = this.get('_py2js_animate');
     if (msgData !== null) {
-      var styles = msgData.style_data;
-      var layout = msgData.layout_data;
-      var trace_indexes = this._normalize_trace_indexes(msgData.style_traces);
-
-      for (var i = 0; i < styles.length; i++) {
-        var style = styles[i];
-        var trace_index = trace_indexes[i];
-        var trace = this.get('_data')[trace_index];
+      const styles = msgData.style_data;
+      const layout = msgData.layout_data;
+      const trace_indexes = this._normalize_trace_indexes(msgData.style_traces);
+
+      for (let i = 0; i < styles.length; i++) {
+        const style = styles[i];
+        const trace_index = trace_indexes[i];
+        const trace = this.get('_data')[trace_index];
         performRelayoutLike(trace, style);
       }
 
@@ -691,13 +699,13 @@ export class FigureModel extends DOMWidgetModel {
    */
   do_removeLayoutProps() {
     /** @type {Py2JsRemoveLayoutPropsMsg} */
-    var msgData: Py2JsRemoveLayoutPropsMsg = this.get(
+    const msgData: Py2JsRemoveLayoutPropsMsg = this.get(
       '_py2js_removeLayoutProps'
     );
 
     if (msgData !== null) {
-      var keyPaths = msgData.remove_props;
-      var layout = this.get('_layout');
+      const keyPaths = msgData.remove_props;
+      const layout = this.get('_layout');
       performRemoveProps(layout, keyPaths);
     }
   }
@@ -707,11 +715,13 @@ export class FigureModel extends DOMWidgetModel {
    */
   do_removeTraceProps() {
     /** @type {Py2JsRemoveTracePropsMsg} */
-    var msgData: Py2JsRemoveTracePropsMsg = this.get('_py2js_removeTraceProps');
+    const msgData: Py2JsRemoveTracePropsMsg = this.get(
+      '_py2js_removeTraceProps'
+    );
     if (msgData !== null) {
-      var keyPaths = msgData.remove_props;
-      var traceIndex = msgData.remove_trace;
-      var trace = this.get('_data')[traceIndex];
+      const keyPaths = msgData.remove_props;
+      const traceIndex = msgData.remove_trace;
+      const trace = this.get('_data')[traceIndex];
 
       performRemoveProps(trace, keyPaths);
     }
@@ -816,7 +826,7 @@ export class FigureView extends DOMWidgetView {
    * is never displayed in a notebook output cell
    */
   perform_render() {
-    var that = this;
+    const that = this;
 
     // Wire up message property callbacks
     // ----------------------------------
@@ -837,8 +847,8 @@ export class FigureView extends DOMWidgetView {
 
     // Get message ids
     // ---------------------
-    var layout_edit_id = this.model.get('_last_layout_edit_id');
-    var trace_edit_id = this.model.get('_last_trace_edit_id');
+    const layout_edit_id = this.model.get('_last_layout_edit_id');
+    const trace_edit_id = this.model.get('_last_trace_edit_id');
 
     // Set view UID
     // ------------
@@ -848,57 +858,56 @@ export class FigureView extends DOMWidgetView {
     // ---------------------------
     // We must clone the model's data and layout properties so that
     // the model is not directly mutated by the Plotly.js library.
-    var initialTraces = _.cloneDeep(this.model.get('_data'));
-    var initialLayout = _.cloneDeep(this.model.get('_layout'));
-    var config = this.model.get('_config');
+    const initialTraces = _.cloneDeep(this.model.get('_data'));
+    const initialLayout = _.cloneDeep(this.model.get('_layout'));
+    const config = this.model.get('_config');
 
-    Plotly.newPlot(that.el, initialTraces, initialLayout, config).then(
-      function () {
-        // ### Send trace deltas ###
-        // We create an array of deltas corresponding to the new
-        // traces.
-        that._sendTraceDeltas(trace_edit_id);
+    Plotly.newPlot(that.el, initialTraces, initialLayout, config).then(() => {
+      // ### Send trace deltas ###
+      // We create an array of deltas corresponding to the new
+      // traces.
+      that._sendTraceDeltas(trace_edit_id);
 
-        // ### Send layout delta ###
-        that._sendLayoutDelta(layout_edit_id);
+      // ### Send layout delta ###
+      that._sendLayoutDelta(layout_edit_id);
 
-        // Wire up plotly event callbacks
-        (<Plotly.PlotlyHTMLElement>that.el).on('plotly_restyle', function (
-          update: any
-        ) {
+      // Wire up plotly event callbacks
+      (<Plotly.PlotlyHTMLElement>that.el).on(
+        'plotly_restyle',
+        (update: any) => {
           that.handle_plotly_restyle(update);
-        });
-        (<Plotly.PlotlyHTMLElement>that.el).on('plotly_relayout', function (
-          update: any
-        ) {
+        }
+      );
+      (<Plotly.PlotlyHTMLElement>that.el).on(
+        'plotly_relayout',
+        (update: any) => {
           that.handle_plotly_relayout(update);
-        });
-        /*
+        }
+      );
+      /*
         (<Plotly.PlotlyHTMLElement>that.el).on("plotly_update", function (update: any) {
           that.handle_plotly_update(update);
         });
 */
-        (<Plotly.PlotlyHTMLElement>that.el).on('plotly_click', function (
-          update: any
-        ) {
-          that.handle_plotly_click(update);
-        });
-        (<Plotly.PlotlyHTMLElement>that.el).on('plotly_hover', function (
-          update: any
-        ) {
-          that.handle_plotly_hover(update);
-        });
-        (<Plotly.PlotlyHTMLElement>that.el).on('plotly_unhover', function (
-          update: any
-        ) {
+      (<Plotly.PlotlyHTMLElement>that.el).on('plotly_click', (update: any) => {
+        that.handle_plotly_click(update);
+      });
+      (<Plotly.PlotlyHTMLElement>that.el).on('plotly_hover', (update: any) => {
+        that.handle_plotly_hover(update);
+      });
+      (<Plotly.PlotlyHTMLElement>that.el).on(
+        'plotly_unhover',
+        (update: any) => {
           that.handle_plotly_unhover(update);
-        });
-        (<Plotly.PlotlyHTMLElement>that.el).on('plotly_selected', function (
-          update: any
-        ) {
+        }
+      );
+      (<Plotly.PlotlyHTMLElement>that.el).on(
+        'plotly_selected',
+        (update: any) => {
           that.handle_plotly_selected(update);
-        });
-        /*
+        }
+      );
+      /*
         (<Plotly.PlotlyHTMLElement>that.el).on("plotly_deselect", function (update: any) {
           that.handle_plotly_deselect(update);
         });
@@ -906,16 +915,15 @@ export class FigureView extends DOMWidgetView {
           that.handle_plotly_doubleclick(update);
         });
 */
-        // Emit event indicating that the widget has finished
-        // rendering
-        var event = new CustomEvent('plotlywidget-after-render', {
-          detail: { element: that.el, viewID: that.viewID },
-        });
+      // Emit event indicating that the widget has finished
+      // rendering
+      const event = new CustomEvent('plotlywidget-after-render', {
+        detail: { element: that.el, viewID: that.viewID },
+      });
 
-        // Dispatch/Trigger/Fire the event
-        document.dispatchEvent(event);
-      }
-    );
+      // Dispatch/Trigger/Fire the event
+      document.dispatchEvent(event);
+    });
   }
 
   /**
@@ -923,7 +931,7 @@ export class FigureView extends DOMWidgetView {
    */
   processLuminoMessage(msg: any) {
     super.processLuminoMessage.apply(this, arguments);
-    var that = this;
+    const that = this;
     switch (msg.type) {
       case 'before-attach':
         // Render an initial empty figure. This establishes with
@@ -941,7 +949,7 @@ export class FigureView extends DOMWidgetView {
           yaxis: axisHidden,
         });
 
-        window.addEventListener('resize', function () {
+        window.addEventListener('resize', () => {
           that.autosizeFigure();
         });
         break;
@@ -957,12 +965,12 @@ export class FigureView extends DOMWidgetView {
   }
 
   autosizeFigure() {
-    var that = this;
-    var layout = that.model.get('_layout');
+    const that = this;
+    const layout = that.model.get('_layout');
     if (_.isNil(layout) || _.isNil(layout.width)) {
       // @ts-ignore
-      Plotly.Plots.resize(that.el).then(function () {
-        var layout_edit_id = that.model.get('_last_layout_edit_id');
+      Plotly.Plots.resize(that.el).then(() => {
+        const layout_edit_id = that.model.get('_last_layout_edit_id');
         that._sendLayoutDelta(layout_edit_id);
       });
     }
@@ -1024,20 +1032,22 @@ export class FigureView extends DOMWidgetView {
    * @returns {null|Points}
    */
   buildPointsObject(data: any): null | Points {
-    var pointsObject: Points;
+    let pointsObject: Points;
     if (data.hasOwnProperty('points')) {
       // Most cartesian plots
-      var pointObjects = data['points'];
-      var numPoints = pointObjects.length;
+      const pointObjects = data['points'];
+      const numPoints = pointObjects.length;
 
-      var hasNestedPointObjects = true;
+      let hasNestedPointObjects = true;
       for (let i = 0; i < numPoints; i++) {
         hasNestedPointObjects =
           hasNestedPointObjects &&
           pointObjects[i].hasOwnProperty('pointNumbers');
-        if (!hasNestedPointObjects) break;
+        if (!hasNestedPointObjects) {
+          break;
+        }
       }
-      var numPointNumbers = numPoints;
+      let numPointNumbers = numPoints;
       if (hasNestedPointObjects) {
         numPointNumbers = 0;
         for (let i = 0; i < numPoints; i++) {
@@ -1052,7 +1062,7 @@ export class FigureView extends DOMWidgetView {
       };
 
       if (hasNestedPointObjects) {
-        var flatPointIndex = 0;
+        let flatPointIndex = 0;
         for (var p = 0; p < numPoints; p++) {
           for (
             let i = 0;
@@ -1075,10 +1085,12 @@ export class FigureView extends DOMWidgetView {
             single_trace &&
             pointsObject['trace_indexes'][i - 1] ===
               pointsObject['trace_indexes'][i];
-          if (!single_trace) break;
+          if (!single_trace) {
+            break;
+          }
         }
         if (single_trace) {
-          pointsObject['point_indexes'].sort(function (a, b) {
+          pointsObject['point_indexes'].sort((a, b) => {
             return a - b;
           });
         }
@@ -1092,7 +1104,7 @@ export class FigureView extends DOMWidgetView {
       }
 
       // Add z if present
-      var hasZ =
+      const hasZ =
         pointObjects[0] !== undefined && pointObjects[0].hasOwnProperty('z');
       if (hasZ) {
         pointsObject['zs'] = new Array(numPoints);
@@ -1114,12 +1126,12 @@ export class FigureView extends DOMWidgetView {
    * @returns {null|InputDeviceState}
    */
   buildInputDeviceStateObject(data: any): null | InputDeviceState {
-    var event = data['event'];
+    const event = data['event'];
     if (event === undefined) {
       return null;
     } else {
       /** @type {InputDeviceState} */
-      var inputDeviceState: InputDeviceState = {
+      const inputDeviceState: InputDeviceState = {
         // Keyboard modifiers
         alt: event['altKey'],
         ctrl: event['ctrlKey'],
@@ -1141,7 +1153,7 @@ export class FigureView extends DOMWidgetView {
    * @returns {null|Selector}
    */
   buildSelectorObject(data: any): null | Selector {
-    var selectorObject: Selector | null;
+    let selectorObject: Selector | null;
 
     if (data.hasOwnProperty('range')) {
       // Box selection
@@ -1183,12 +1195,12 @@ export class FigureView extends DOMWidgetView {
     }
 
     // Unpack data
-    var styleData = data[0];
-    var styleTraces = data[1];
+    const styleData = data[0];
+    const styleTraces = data[1];
 
     // Construct restyle message to send to the Python side
     /** @type {Js2PyRestyleMsg} */
-    var restyleMsg: Js2PyRestyleMsg = {
+    const restyleMsg: Js2PyRestyleMsg = {
       style_data: styleData,
       style_traces: styleTraces,
       source_view_id: this.viewID,
@@ -1214,7 +1226,7 @@ export class FigureView extends DOMWidgetView {
     }
 
     /** @type {Js2PyRelayoutMsg} */
-    var relayoutMsg: Js2PyRelayoutMsg = {
+    const relayoutMsg: Js2PyRelayoutMsg = {
       relayout_data: data,
       source_view_id: this.viewID,
     };
@@ -1239,7 +1251,7 @@ export class FigureView extends DOMWidgetView {
     }
 
     /** @type {Js2PyUpdateMsg} */
-    var updateMsg: Js2PyUpdateMsg = {
+    const updateMsg: Js2PyUpdateMsg = {
       style_data: data['data'][0],
       style_traces: data['data'][1],
       layout_data: data['layout'],
@@ -1312,7 +1324,7 @@ export class FigureView extends DOMWidgetView {
     }
 
     /** @type {Js2PyPointsCallbackMsg} */
-    var pointsMsg: Js2PyPointsCallbackMsg = {
+    const pointsMsg: Js2PyPointsCallbackMsg = {
       event_type: event_type,
       points: this.buildPointsObject(data) as Points,
       device_state: this.buildInputDeviceStateObject(data) as InputDeviceState,
@@ -1336,16 +1348,16 @@ export class FigureView extends DOMWidgetView {
    */
   do_addTraces() {
     /** @type {Py2JsAddTracesMsg} */
-    var msgData: Py2JsAddTracesMsg = this.model.get('_py2js_addTraces');
+    const msgData: Py2JsAddTracesMsg = this.model.get('_py2js_addTraces');
 
     if (msgData !== null) {
-      var that = this;
-      Plotly.addTraces(this.el, msgData.trace_data).then(function () {
+      const that = this;
+      Plotly.addTraces(this.el, msgData.trace_data).then(() => {
         // ### Send trace deltas ###
         that._sendTraceDeltas(msgData.trace_edit_id);
 
         // ### Send layout delta ###
-        var layout_edit_id = msgData.layout_edit_id;
+        const layout_edit_id = msgData.layout_edit_id;
         that._sendLayoutDelta(layout_edit_id);
       });
     }
@@ -1356,18 +1368,18 @@ export class FigureView extends DOMWidgetView {
    */
   do_deleteTraces() {
     /** @type {Py2JsDeleteTracesMsg} */
-    var msgData: Py2JsDeleteTracesMsg = this.model.get('_py2js_deleteTraces');
+    const msgData: Py2JsDeleteTracesMsg = this.model.get('_py2js_deleteTraces');
 
     if (msgData !== null) {
-      var delete_inds = msgData.delete_inds;
-      var that = this;
-      Plotly.deleteTraces(this.el, delete_inds).then(function () {
+      const delete_inds = msgData.delete_inds;
+      const that = this;
+      Plotly.deleteTraces(this.el, delete_inds).then(() => {
         // ### Send trace deltas ###
-        var trace_edit_id = msgData.trace_edit_id;
+        const trace_edit_id = msgData.trace_edit_id;
         that._sendTraceDeltas(trace_edit_id);
 
         // ### Send layout delta ###
-        var layout_edit_id = msgData.layout_edit_id;
+        const layout_edit_id = msgData.layout_edit_id;
         that._sendLayoutDelta(layout_edit_id);
       });
     }
@@ -1378,16 +1390,16 @@ export class FigureView extends DOMWidgetView {
    */
   do_moveTraces() {
     /** @type {Py2JsMoveTracesMsg} */
-    var msgData: Py2JsMoveTracesMsg = this.model.get('_py2js_moveTraces');
+    const msgData: Py2JsMoveTracesMsg = this.model.get('_py2js_moveTraces');
 
     if (msgData !== null) {
       // Unpack message
-      var currentInds = msgData.current_trace_inds;
-      var newInds = msgData.new_trace_inds;
+      const currentInds = msgData.current_trace_inds;
+      const newInds = msgData.new_trace_inds;
 
       // Check if the new trace indexes are actually different than
       // the current indexes
-      var inds_equal = _.isEqual(currentInds, newInds);
+      const inds_equal = _.isEqual(currentInds, newInds);
 
       if (!inds_equal) {
         Plotly.moveTraces(this.el, currentInds, newInds);
@@ -1400,10 +1412,10 @@ export class FigureView extends DOMWidgetView {
    */
   do_restyle() {
     /** @type {Py2JsRestyleMsg} */
-    var msgData: Py2JsRestyleMsg = this.model.get('_py2js_restyle');
+    const msgData: Py2JsRestyleMsg = this.model.get('_py2js_restyle');
     if (msgData !== null) {
-      var restyleData = msgData.restyle_data;
-      var traceIndexes = (this.model as FigureModel)._normalize_trace_indexes(
+      const restyleData = msgData.restyle_data;
+      const traceIndexes = (this.model as FigureModel)._normalize_trace_indexes(
         msgData.restyle_traces
       );
 
@@ -1416,7 +1428,7 @@ export class FigureView extends DOMWidgetView {
       this._sendTraceDeltas(msgData.trace_edit_id);
 
       // ### Send layout delta ###
-      var layout_edit_id = msgData.layout_edit_id;
+      const layout_edit_id = msgData.layout_edit_id;
       this._sendLayoutDelta(layout_edit_id);
     }
   }
@@ -1426,16 +1438,16 @@ export class FigureView extends DOMWidgetView {
    */
   do_relayout() {
     /** @type {Py2JsRelayoutMsg} */
-    var msgData: Py2JsRelayoutMsg = this.model.get('_py2js_relayout');
+    const msgData: Py2JsRelayoutMsg = this.model.get('_py2js_relayout');
     if (msgData !== null) {
       if (msgData.source_view_id !== this.viewID) {
-        var relayoutData = msgData.relayout_data;
+        const relayoutData = msgData.relayout_data;
         relayoutData['_doNotReportToPy'] = true;
         Plotly.relayout(this.el, msgData.relayout_data);
       }
 
       // ### Send layout delta ###
-      var layout_edit_id = msgData.layout_edit_id;
+      const layout_edit_id = msgData.layout_edit_id;
       this._sendLayoutDelta(layout_edit_id);
     }
   }
@@ -1445,12 +1457,12 @@ export class FigureView extends DOMWidgetView {
    */
   do_update() {
     /** @type {Py2JsUpdateMsg} */
-    var msgData: Py2JsUpdateMsg = this.model.get('_py2js_update');
+    const msgData: Py2JsUpdateMsg = this.model.get('_py2js_update');
 
     if (msgData !== null) {
-      var style = msgData.style_data || {};
-      var layout = msgData.layout_data || {};
-      var traceIndexes = (this.model as FigureModel)._normalize_trace_indexes(
+      const style = msgData.style_data || {};
+      const layout = msgData.layout_data || {};
+      const traceIndexes = (this.model as FigureModel)._normalize_trace_indexes(
         msgData.style_traces
       );
 
@@ -1463,7 +1475,7 @@ export class FigureView extends DOMWidgetView {
       this._sendTraceDeltas(msgData.trace_edit_id);
 
       // ### Send layout delta ###
-      var layout_edit_id = msgData.layout_edit_id;
+      const layout_edit_id = msgData.layout_edit_id;
       this._sendLayoutDelta(layout_edit_id);
     }
   }
@@ -1473,37 +1485,37 @@ export class FigureView extends DOMWidgetView {
    */
   do_animate() {
     /** @type {Py2JsAnimateMsg} */
-    var msgData: Py2JsAnimateMsg = this.model.get('_py2js_animate');
+    const msgData: Py2JsAnimateMsg = this.model.get('_py2js_animate');
 
     if (msgData !== null) {
       // Unpack params
       // var animationData = msgData[0];
-      var animationOpts = msgData.animation_opts;
+      const animationOpts = msgData.animation_opts;
 
-      var styles = msgData.style_data;
-      var layout = msgData.layout_data;
-      var traceIndexes = (this.model as FigureModel)._normalize_trace_indexes(
+      const styles = msgData.style_data;
+      const layout = msgData.layout_data;
+      const traceIndexes = (this.model as FigureModel)._normalize_trace_indexes(
         msgData.style_traces
       );
 
-      var animationData: any = {
+      const animationData: any = {
         data: styles,
         layout: layout,
         traces: traceIndexes,
       };
 
       animationData['_doNotReportToPy'] = true;
-      var that = this;
+      const that = this;
 
       // @ts-ignore
-      Plotly.animate(this.el, animationData, animationOpts).then(function () {
+      Plotly.animate(this.el, animationData, animationOpts).then(() => {
         // ### Send trace deltas ###
         // We create an array of deltas corresponding to the
         // animated traces.
         that._sendTraceDeltas(msgData.trace_edit_id);
 
         // ### Send layout delta ###
-        var layout_edit_id = msgData.layout_edit_id;
+        const layout_edit_id = msgData.layout_edit_id;
         that._sendLayoutDelta(layout_edit_id);
       });
     }
@@ -1519,13 +1531,13 @@ export class FigureView extends DOMWidgetView {
    */
   _sendLayoutDelta(layout_edit_id: any) {
     // ### Handle layout delta ###
-    var layout_delta = createDeltaObject(
+    const layout_delta = createDeltaObject(
       this.getFullLayout(),
       this.model.get('_layout')
     );
 
     /** @type{Js2PyLayoutDeltaMsg} */
-    var layoutDeltaMsg: Js2PyLayoutDeltaMsg = {
+    const layoutDeltaMsg: Js2PyLayoutDeltaMsg = {
       layout_delta: layout_delta,
       layout_edit_id: layout_edit_id,
     };
@@ -1543,13 +1555,13 @@ export class FigureView extends DOMWidgetView {
    * @private
    */
   _sendTraceDeltas(trace_edit_id: any) {
-    var trace_data = this.model.get('_data');
-    var traceIndexes = _.range(trace_data.length);
-    var trace_deltas = new Array(traceIndexes.length);
+    const trace_data = this.model.get('_data');
+    const traceIndexes = _.range(trace_data.length);
+    const trace_deltas = new Array(traceIndexes.length);
 
-    var fullData = this.getFullData();
-    for (var i = 0; i < traceIndexes.length; i++) {
-      var traceInd = traceIndexes[i];
+    const fullData = this.getFullData();
+    for (let i = 0; i < traceIndexes.length; i++) {
+      const traceInd = traceIndexes[i];
       trace_deltas[i] = createDeltaObject(
         (fullData as any)[traceInd],
         trace_data[traceInd]
@@ -1557,7 +1569,7 @@ export class FigureView extends DOMWidgetView {
     }
 
     /** @type{Js2PyTraceDeltasMsg} */
-    var traceDeltasMsg: Js2PyTraceDeltasMsg = {
+    const traceDeltasMsg: Js2PyTraceDeltasMsg = {
       trace_deltas: trace_deltas,
       trace_edit_id: trace_edit_id,
     };
@@ -1584,7 +1596,7 @@ const numpy_dtype_to_typedarray_type = {
 };
 
 function serializeTypedArray(v: ArrayConstructor) {
-  var numpyType;
+  let numpyType;
   if (v instanceof Int8Array) {
     numpyType = 'int8';
   } else if (v instanceof Int16Array) {
@@ -1605,7 +1617,7 @@ function serializeTypedArray(v: ArrayConstructor) {
     // Don't understand it, return as is
     return v;
   }
-  var res = {
+  const res = {
     dtype: numpyType,
     shape: [v.length],
     value: v.buffer,
@@ -1617,20 +1629,20 @@ function serializeTypedArray(v: ArrayConstructor) {
  * ipywidget JavaScript -> Python serializer
  */
 function js2py_serializer(v: any, widgetManager?: any) {
-  var res: any;
+  let res: any;
 
   if (_.isTypedArray(v)) {
     res = serializeTypedArray(v);
   } else if (Array.isArray(v)) {
     // Serialize array elements recursively
     res = new Array(v.length);
-    for (var i = 0; i < v.length; i++) {
+    for (let i = 0; i < v.length; i++) {
       res[i] = js2py_serializer(v[i]);
     }
   } else if (_.isPlainObject(v)) {
     // Serialize object properties recursively
     res = {};
-    for (var p in v) {
+    for (const p in v) {
       if (v.hasOwnProperty(p)) {
         res[p] = js2py_serializer(v[p]);
       }
@@ -1651,12 +1663,12 @@ function js2py_serializer(v: any, widgetManager?: any) {
  * ipywidget Python -> Javascript deserializer
  */
 function py2js_deserializer(v: any, widgetManager?: any) {
-  var res: any;
+  let res: any;
 
   if (Array.isArray(v)) {
     // Deserialize array elements recursively
     res = new Array(v.length);
-    for (var i = 0; i < v.length; i++) {
+    for (let i = 0; i < v.length; i++) {
       res[i] = py2js_deserializer(v[i]);
     }
   } else if (_.isPlainObject(v)) {
@@ -1672,13 +1684,13 @@ function py2js_deserializer(v: any, widgetManager?: any) {
       // This was renamed `value` in 3.2 to work around a naming conflict
       // when saving widget state to a notebook.
       // @ts-ignore
-      var typedarray_type = numpy_dtype_to_typedarray_type[v.dtype];
-      var buffer = _.has(v, 'value') ? v.value.buffer : v.buffer.buffer;
+      const typedarray_type = numpy_dtype_to_typedarray_type[v.dtype];
+      const buffer = _.has(v, 'value') ? v.value.buffer : v.buffer.buffer;
       res = new typedarray_type(buffer);
     } else {
       // Deserialize object properties recursively
       res = {};
-      for (var p in v) {
+      for (const p in v) {
         if (v.hasOwnProperty(p)) {
           res[p] = py2js_deserializer(v[p]);
         }
@@ -1749,13 +1761,13 @@ function fullMergeCustomizer(objValue: any, srcValue: any, key: string) {
  */
 function performRelayoutLike(parentObj: any, relayoutData: any) {
   // Perform a relayout style operation on a given parent object
-  for (var rawKey in relayoutData) {
+  for (const rawKey in relayoutData) {
     if (!relayoutData.hasOwnProperty(rawKey)) {
       continue;
     }
 
     // Extract value for this key
-    var relayoutVal = relayoutData[rawKey];
+    const relayoutVal = relayoutData[rawKey];
 
     // Set property value
     if (relayoutVal === null) {
@@ -1796,25 +1808,25 @@ function performRestyleLike(
   restyleTraces: number[]
 ) {
   // Loop over the properties of restyleData
-  for (var rawKey in restyleData) {
+  for (const rawKey in restyleData) {
     if (!restyleData.hasOwnProperty(rawKey)) {
       continue;
     }
 
     // Extract value for property and normalize into a value list
-    var valArray = restyleData[rawKey];
+    let valArray = restyleData[rawKey];
     if (!Array.isArray(valArray)) {
       valArray = [valArray];
     }
 
     // Loop over the indexes of the traces being restyled
-    for (var i = 0; i < restyleTraces.length; i++) {
+    for (let i = 0; i < restyleTraces.length; i++) {
       // Get trace object
-      var traceInd = restyleTraces[i];
-      var trace = parentArray[traceInd];
+      const traceInd = restyleTraces[i];
+      const trace = parentArray[traceInd];
 
       // Extract value for this trace
-      var singleVal = valArray[i % valArray.length];
+      const singleVal = valArray[i % valArray.length];
 
       // Set property value
       if (singleVal === null) {
@@ -1851,15 +1863,15 @@ function performMoveTracesLike(
   newInds: number[]
 ) {
   // ### Remove by currentInds in reverse order ###
-  var movingTracesData: any[] = [];
-  for (var ci = currentInds.length - 1; ci >= 0; ci--) {
+  let movingTracesData: any[] = [];
+  for (let ci = currentInds.length - 1; ci >= 0; ci--) {
     // Insert moving parentArray at beginning of the list
     movingTracesData.splice(0, 0, parentArray[currentInds[ci]]);
     parentArray.splice(currentInds[ci], 1);
   }
 
   // ### Sort newInds and movingTracesData by newInds ###
-  var newIndexSortedArrays = _(newInds)
+  const newIndexSortedArrays = _(newInds)
     .zip(movingTracesData)
     .sortBy(0)
     .unzip()
@@ -1869,7 +1881,7 @@ function performMoveTracesLike(
   movingTracesData = newIndexSortedArrays[1];
 
   // ### Insert by newInds in forward order ###
-  for (var ni = 0; ni < newInds.length; ni++) {
+  for (let ni = 0; ni < newInds.length; ni++) {
     parentArray.splice(newInds[ni], 0, movingTracesData[ni]);
   }
 }
@@ -1897,8 +1909,8 @@ function performRemoveProps(
   parentObj: object,
   keyPaths: Array<Array<number | string>>
 ) {
-  for (var i = 0; i < keyPaths.length; i++) {
-    var keyPath = keyPaths[i];
+  for (let i = 0; i < keyPaths.length; i++) {
+    const keyPath = keyPaths[i];
     _.unset(parentObj, keyPath);
   }
 }
@@ -1933,7 +1945,7 @@ function performRemoveProps(
  */
 function createDeltaObject(fullObj: any, removeObj: any) {
   // Initialize result as object or array
-  var res: any;
+  let res: any;
   if (Array.isArray(fullObj)) {
     res = new Array(fullObj.length);
   } else {
@@ -1946,7 +1958,7 @@ function createDeltaObject(fullObj: any, removeObj: any) {
   }
 
   // Iterate over object properties or array indices
-  for (var p in fullObj) {
+  for (const p in fullObj) {
     if (
       p[0] !== '_' && // Don't consider private properties
       fullObj.hasOwnProperty(p) && // Exclude parent properties
@@ -1963,14 +1975,14 @@ function createDeltaObject(fullObj: any, removeObj: any) {
 
         // property has non-null value in fullObj that doesn't
         // match the value in removeObj
-        var fullVal = fullObj[p];
+        const fullVal = fullObj[p];
         if (removeObj.hasOwnProperty(p) && typeof fullVal === 'object') {
           // Recurse over object properties
           if (Array.isArray(fullVal)) {
             if (fullVal.length > 0 && typeof fullVal[0] === 'object') {
               // We have an object array
               res[p] = new Array(fullVal.length);
-              for (var i = 0; i < fullVal.length; i++) {
+              for (let i = 0; i < fullVal.length; i++) {
                 if (!Array.isArray(removeObj[p]) || removeObj[p].length <= i) {
                   res[p][i] = fullVal[i];
                 } else {
@@ -1983,7 +1995,7 @@ function createDeltaObject(fullObj: any, removeObj: any) {
             }
           } else {
             // object
-            var full_obj = createDeltaObject(fullVal, removeObj[p]);
+            const full_obj = createDeltaObject(fullVal, removeObj[p]);
             if (Object.keys(full_obj).length > 0) {
               // new object is not empty
               res[p] = full_obj;
@@ -2011,19 +2023,25 @@ function randstr(
   base?: number,
   _recursion?: number
 ): string {
-  if (!base) base = 16;
-  if (bits === undefined) bits = 24;
-  if (bits <= 0) return '0';
+  if (!base) {
+    base = 16;
+  }
+  if (bits === undefined) {
+    bits = 24;
+  }
+  if (bits <= 0) {
+    return '0';
+  }
 
-  var digits = Math.log(Math.pow(2, bits)) / Math.log(base);
-  var res = '';
-  var i, b, x;
+  let digits = Math.log(Math.pow(2, bits)) / Math.log(base);
+  let res = '';
+  let i, b, x;
 
   for (i = 2; digits === Infinity; i *= 2) {
     digits = (Math.log(Math.pow(2, bits / i)) / Math.log(base)) * i;
   }
 
-  var rem = digits - Math.floor(digits);
+  const rem = digits - Math.floor(digits);
 
   for (i = 0; i < Math.floor(digits); i++) {
     x = Math.floor(Math.random() * base).toString(base);
@@ -2036,7 +2054,7 @@ function randstr(
     res = x + res;
   }
 
-  var parsed = parseInt(res, base);
+  const parsed = parseInt(res, base);
   if (
     (existing && existing[res]) ||
     (parsed !== Infinity && parsed >= Math.pow(2, bits))
@@ -2046,5 +2064,7 @@ function randstr(
       return res;
     }
     return randstr(existing, bits, base, (_recursion || 0) + 1);
-  } else return res;
+  } else {
+    return res;
+  }
 }
diff --git a/packages/react/src/jupyter/kernel/Kernel.ts b/packages/react/src/jupyter/kernel/Kernel.ts
index 84607ea5..080d8d8d 100755
--- a/packages/react/src/jupyter/kernel/Kernel.ts
+++ b/packages/react/src/jupyter/kernel/Kernel.ts
@@ -120,7 +120,7 @@ export class Kernel {
       );
       this._kernelConnection.info.then(info => {
         this._info = info;
-        console.log(`Kernel Info`, this.toJSON());
+        console.log('Kernel Info', this.toJSON());
       });
     }
   }
diff --git a/packages/react/src/jupyter/kernel/KernelExecutor.ts b/packages/react/src/jupyter/kernel/KernelExecutor.ts
index 74621a6e..fae83a60 100644
--- a/packages/react/src/jupyter/kernel/KernelExecutor.ts
+++ b/packages/react/src/jupyter/kernel/KernelExecutor.ts
@@ -101,9 +101,11 @@ export class KernelExecutor {
         this._modelChanged.emit(this._model);
         break;
       case 'status':
-        // execution_state: 'busy' 'starting' 'terminating' 'restarting' 'initializing' 'connecting' 'disconnected' 'dead' 'unknown' 'idle'
-        const executionState = (message.content as any).execution_state;
-        executionState;
+        {
+          // execution_state: 'busy' 'starting' 'terminating' 'restarting' 'initializing' 'connecting' 'disconnected' 'dead' 'unknown' 'idle'
+          const executionState = (message.content as any).execution_state;
+          executionState;
+        }
         break;
       default:
         break;
@@ -118,16 +120,18 @@ export class KernelExecutor {
     this._shellMessageHooks.forEach(hook => hook(message));
     switch (messageType) {
       case 'execute_reply':
-        const output: IOutput = {
-          output_type: 'display_data',
-          data: (message.content as IExecuteResult).data as IMimeBundle,
-          metadata: {},
-        };
-        this._outputs.push(message.content as IExecuteResult);
-        this._outputsChanged.emit(this._outputs);
-        this._model.add(output);
-        this.executeReplyReceived.emit(this._model);
-        this._executedResolve(this._model);
+        {
+          const output: IOutput = {
+            output_type: 'display_data',
+            data: (message.content as IExecuteResult).data as IMimeBundle,
+            metadata: {},
+          };
+          this._outputs.push(message.content as IExecuteResult);
+          this._outputsChanged.emit(this._outputs);
+          this._model.add(output);
+          this.executeReplyReceived.emit(this._model);
+          this._executedResolve(this._model);
+        }
         break;
       default:
         break;
diff --git a/packages/react/src/jupyter/lab/notebook/content/plugin.ts b/packages/react/src/jupyter/lab/notebook/content/plugin.ts
index f9a4a736..8a5ca6e4 100644
--- a/packages/react/src/jupyter/lab/notebook/content/plugin.ts
+++ b/packages/react/src/jupyter/lab/notebook/content/plugin.ts
@@ -15,16 +15,17 @@ import CountdownPromptContentFactory from './CountdownContentFactory';
 /**
  * The notebook cell factory provider.
  */
-const contentFactoryPlugin: JupyterFrontEndPlugin<NotebookPanel.IContentFactory> = {
-  id: '@datalayer/jupyter-react:notebook-content-factory',
-  description: 'Provides the notebook cell factory.',
-  provides: NotebookPanel.IContentFactory,
-  requires: [IEditorServices],
-  autoStart: true,
-  activate: (app: JupyterFrontEnd, editorServices: IEditorServices) => {
-    const editorFactory = editorServices.factoryService.newInlineEditor;
-    return new CountdownPromptContentFactory({ editorFactory });
-  },
-};
+const contentFactoryPlugin: JupyterFrontEndPlugin<NotebookPanel.IContentFactory> =
+  {
+    id: '@datalayer/jupyter-react:notebook-content-factory',
+    description: 'Provides the notebook cell factory.',
+    provides: NotebookPanel.IContentFactory,
+    requires: [IEditorServices],
+    autoStart: true,
+    activate: (app: JupyterFrontEnd, editorServices: IEditorServices) => {
+      const editorFactory = editorServices.factoryService.newInlineEditor;
+      return new CountdownPromptContentFactory({ editorFactory });
+    },
+  };
 
 export default contentFactoryPlugin;
diff --git a/packages/react/src/jupyter/lite/LiteServer.ts b/packages/react/src/jupyter/lite/LiteServer.ts
index 48993aa8..bc0f5c08 100644
--- a/packages/react/src/jupyter/lite/LiteServer.ts
+++ b/packages/react/src/jupyter/lite/LiteServer.ts
@@ -18,16 +18,17 @@ function* activePlugins(
 ): Generator<JupyterLiteServerPlugin<any>> {
   // Handle commonjs or es2015 modules.
   let exports;
+  // eslint-disable-next-line no-prototype-builtins
   if (extension.hasOwnProperty('__esModule')) {
     exports = extension.default;
   } else {
     // CommonJS exports.
     exports = extension;
   }
-  let plugins: JupyterLiteServerPlugin<any>[] = Array.isArray(exports)
+  const plugins: JupyterLiteServerPlugin<any>[] = Array.isArray(exports)
     ? exports
     : [exports];
-  for (let plugin of plugins) {
+  for (const plugin of plugins) {
     if (PageConfig.Extension.isDisabled(plugin.id)) {
       console.info(`JupyterLite plugin '${plugin.id}' has been disabled.`);
       continue;
@@ -50,7 +51,7 @@ export async function createLiteServer(): Promise<JupyterLiteServer> {
 
   // Load the base serverlite extensions.
   const baseServerExtension = await import('@jupyterlite/server-extension');
-  for (let plugin of activePlugins(baseServerExtension)) {
+  for (const plugin of activePlugins(baseServerExtension)) {
     litePluginsToRegister.push(plugin);
   }
 
diff --git a/packages/react/src/jupyter/renderers/plotly/PlotlyRenderer.ts b/packages/react/src/jupyter/renderers/plotly/PlotlyRenderer.ts
index 24a5b67c..504c6838 100644
--- a/packages/react/src/jupyter/renderers/plotly/PlotlyRenderer.ts
+++ b/packages/react/src/jupyter/renderers/plotly/PlotlyRenderer.ts
@@ -94,7 +94,7 @@ export class RenderedPlotly extends Widget implements IRenderMime.IRenderer {
 
   private hideGraph() {
     // Hide the graph if there is one
-    let el = <HTMLDivElement>this.node.querySelector('.plot-container');
+    const el = <HTMLDivElement>this.node.querySelector('.plot-container');
     if (el !== null && el !== undefined) {
       el.style.display = 'none';
     }
@@ -102,7 +102,7 @@ export class RenderedPlotly extends Widget implements IRenderMime.IRenderer {
 
   private showGraph() {
     // Show the graph if there is one
-    let el = <HTMLDivElement>this.node.querySelector('.plot-container');
+    const el = <HTMLDivElement>this.node.querySelector('.plot-container');
     if (el !== null && el !== undefined) {
       el.style.display = 'block';
     }
@@ -110,7 +110,7 @@ export class RenderedPlotly extends Widget implements IRenderMime.IRenderer {
 
   private hideImage() {
     // Hide the image element
-    let el = <HTMLImageElement>this.node.querySelector('.plot-img');
+    const el = <HTMLImageElement>this.node.querySelector('.plot-img');
     if (el !== null && el !== undefined) {
       el.style.display = 'none';
     }
@@ -118,7 +118,7 @@ export class RenderedPlotly extends Widget implements IRenderMime.IRenderer {
 
   private showImage() {
     // Show the image element
-    let el = <HTMLImageElement>this.node.querySelector('.plot-img');
+    const el = <HTMLImageElement>this.node.querySelector('.plot-img');
     if (el !== null && el !== undefined) {
       el.style.display = 'block';
     }
diff --git a/packages/react/stories/Cell.stories.tsx b/packages/react/stories/Cell.stories.tsx
index cfb5ae9f..9684349c 100644
--- a/packages/react/stories/Cell.stories.tsx
+++ b/packages/react/stories/Cell.stories.tsx
@@ -10,32 +10,70 @@ import { Jupyter, Cell } from './../src';
 
 const meta: Meta<typeof Cell> = {
   title: 'Components/Cell',
+  component: Cell,
+  argTypes: {
+    browser: {
+      control: 'radio',
+      options: ['true', 'false', '@jupyterlite/javascript-kernel-extension'],
+      table: {
+        // Switching live does not work
+        disable: true,
+      },
+    },
+    source: {
+      control: 'text',
+    },
+    autoStart: {
+      control: 'boolean',
+    },
+  },
 } as Meta<typeof Cell>;
 
 export default meta;
 
-type Story = StoryObj<typeof Cell>;
+type Story = StoryObj<typeof Cell | typeof Jupyter | { browser: string }>;
 
 const Template = (args, { globals: { labComparison } }) => {
-  const Tag = `${(args.as as string) ?? 'span'}` as keyof JSX.IntrinsicElements;
+  const { browser, ...others } = args;
+  const lite = {
+    true: true,
+    false: false,
+    '@jupyterlite/javascript-kernel-extension': import(
+      '@jupyterlite/javascript-kernel-extension'
+    ),
+  }[args.browser];
+
+  const kernelName =
+    args.browser === '@jupyterlite/javascript-kernel-extension'
+      ? 'javascript'
+      : undefined;
+
   return (
     <Jupyter
+      lite={lite}
+      defaultKernelName={kernelName}
       jupyterServerHttpUrl="https://oss.datalayer.tech/api/jupyter"
       jupyterServerWsUrl="wss://oss.datalayer.tech/api/jupyter"
       jupyterToken="60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6"
     >
-      <Cell {...args} />
+      <Cell {...others} />
     </Jupyter>
   );
 };
 
 export const Default: Story = Template.bind({});
+Default.args = {
+  browser: 'false',
+  source: '',
+  autoStart: false,
+};
 
 export const Playground: Story = {
   render: Template.bind({}),
 };
 
 Playground.args = {
+  ...Default.args,
   source: `import numpy as np
 import matplotlib.pyplot as plt
 x1 = np.linspace(0.0, 5.0)
@@ -53,11 +91,12 @@ plt.show()`,
   autoStart: true,
 };
 
-Playground.argTypes = {
-  source: {
-    type: 'string',
-  },
-  autoStart: {
-    type: 'boolean',
-  },
+export const LitePython: Story = Template.bind({});
+LitePython.args = {
+  ...Playground.args,
+  browser: 'true',
+  source: `import sys
+print(f"{sys.platform=}")
+
+${Playground.args.source ?? ''}`,
 };
diff --git a/packages/react/stories/Console.stories.tsx b/packages/react/stories/Console.stories.tsx
index f9475e44..5927c84e 100644
--- a/packages/react/stories/Console.stories.tsx
+++ b/packages/react/stories/Console.stories.tsx
@@ -10,9 +10,20 @@ import { Jupyter, Console } from './../src';
 
 const meta: Meta<typeof Console> = {
   title: 'Components/Console',
+  component: Console,
   argTypes: {
-    lite: {
+    browser: {
+      control: 'radio',
+      options: ['true', 'false', '@jupyterlite/javascript-kernel-extension'],
       table: {
+        // Switching live does not work
+        disable: true,
+      },
+    },
+    code: {
+      control: 'text',
+      table: {
+        // Switching live does not work
         disable: true,
       },
     },
@@ -21,7 +32,9 @@ const meta: Meta<typeof Console> = {
 
 export default meta;
 
-type Story = StoryObj<typeof Console>;
+type Story = StoryObj<
+  typeof Console | typeof Jupyter | { browser: string; code: string }
+>;
 
 const Template = (args, { globals: { labComparison } }) => {
   const lite = {
@@ -30,10 +43,10 @@ const Template = (args, { globals: { labComparison } }) => {
     '@jupyterlite/javascript-kernel-extension': import(
       '@jupyterlite/javascript-kernel-extension'
     ),
-  }[args.lite];
+  }[args.browser];
 
   const kernelName =
-    args.lite === '@jupyterlite/javascript-kernel-extension'
+    args.browser === '@jupyterlite/javascript-kernel-extension'
       ? 'javascript'
       : undefined;
 
@@ -45,30 +58,26 @@ const Template = (args, { globals: { labComparison } }) => {
       jupyterServerWsUrl="wss://oss.datalayer.tech/api/jupyter"
       jupyterToken="60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6"
     >
-      <Console
-        code={
-          [
-            "print('👋 Hello Jupyter Console')"
-          ]
-        }
-      />
+      <Console code={args.code ? args.code.split('\n') : undefined} />
     </Jupyter>
   );
 };
 
 export const Default: Story = Template.bind({});
 Default.args = {
-  lite: 'false',
+  browser: 'false',
+  code: "print('👋 Hello Jupyter Console')",
 };
 
 export const LitePython: Story = Template.bind({});
 LitePython.args = {
   ...Default.args,
-  lite: true,
+  browser: 'true',
 };
 
 export const LiteJavascript: Story = Template.bind({});
 LiteJavascript.args = {
   ...Default.args,
-  lite: '@jupyterlite/javascript-kernel-extension',
+  browser: '@jupyterlite/javascript-kernel-extension',
+  code: "a = 'hello';\nArray(4).fill(`${a} the world`);",
 };
diff --git a/packages/react/stories/Notebook.stories.tsx b/packages/react/stories/Notebook.stories.tsx
index cf0cbf7b..18ba1a74 100644
--- a/packages/react/stories/Notebook.stories.tsx
+++ b/packages/react/stories/Notebook.stories.tsx
@@ -10,45 +10,202 @@ import React from 'react';
 
 const meta: Meta<typeof Notebook> = {
   title: 'Components/Notebook',
+  component: Notebook,
+  argTypes: {
+    browser: {
+      control: 'radio',
+      options: ['true', 'false', '@jupyterlite/javascript-kernel-extension'],
+      table: {
+        // Switching live does not work
+        disable: true,
+      },
+    },
+  },
 } as Meta<typeof Notebook>;
 
 export default meta;
 
-type Story = StoryObj<typeof Notebook>;
+type Story = StoryObj<typeof Notebook | typeof Jupyter | { browser: string }>;
 
 const Template = (args, { globals: { labComparison } }) => {
-  const Tag = `${(args.as as string) ?? 'span'}` as keyof JSX.IntrinsicElements;
+  const { browser, ...others } = args;
+  const lite = {
+    true: true,
+    false: false,
+    '@jupyterlite/javascript-kernel-extension': import(
+      '@jupyterlite/javascript-kernel-extension'
+    ),
+  }[args.browser];
+
+  const kernelName =
+    args.browser === '@jupyterlite/javascript-kernel-extension'
+      ? 'javascript'
+      : undefined;
+
   return (
     <Jupyter
+      lite={lite}
+      defaultKernelName={kernelName}
       jupyterServerHttpUrl="https://oss.datalayer.tech/api/jupyter"
       jupyterServerWsUrl="wss://oss.datalayer.tech/api/jupyter"
       jupyterToken="60c1661cc408f978c309d04157af55c9588ff9557c9380e4fb50785750703da6"
     >
-      <Notebook {...args} />
+      <Notebook {...others} />
     </Jupyter>
   );
 };
 
 export const Default: Story = Template.bind({});
+Default.args = {
+  browser: 'false',
+  path: undefined,
+  uid: undefined,
+  cellMetadataPanel: false,
+  cellSidebarMargin: 120,
+  height: '100vh',
+  ipywidgets: 'lab',
+  maxHeight: '100vh',
+  nbgrader: false,
+  readOnly: false,
+  renderers: [],
+};
 
 export const Playground: Story = {
   render: Template.bind({}),
 };
-
 Playground.args = {
+  ...Default.args,
   path: 'ipywidgets.ipynb',
   ipywidgets: 'classic',
   uid: 'uid-1',
 };
 
-Playground.argTypes = {
-  path: {
-    type: 'string',
-  },
-  ipywidgets: {
-    type: 'string',
-  },
-  uid: {
-    type: 'string',
+const WIDGETS_EXAMPLE = {
+  cells: [
+    {
+      cell_type: 'code',
+      execution_count: null,
+      id: '3a86eccf-352d-480d-b1b0-4cf355921be9',
+      metadata: {
+        trusted: false,
+      },
+      outputs: [],
+      source:
+        "import piplite\nawait piplite.install('ipywidgets')\nawait piplite.install('bqplot')\nawait piplite.install('ipyleaflet')\nawait piplite.install('ipyreact')\nawait piplite.install('plotly')\nawait piplite.install('nbformat')\nawait piplite.install('ipympl')",
+    },
+    {
+      cell_type: 'code',
+      execution_count: null,
+      id: '3a86eccf-352d-480d-b1b0-4cf355921be9',
+      metadata: {
+        trusted: false,
+      },
+      outputs: [],
+      source: 'import ipywidgets as widgets\nw = widgets.IntSlider()\nw',
+    },
+    {
+      cell_type: 'code',
+      execution_count: null,
+      id: '3c41e451-a5eb-4494-87a0-94d39ccf9db8',
+      metadata: {
+        trusted: false,
+      },
+      outputs: [],
+      source: 'from IPython.display import display\ndisplay(w)',
+    },
+    {
+      cell_type: 'code',
+      execution_count: null,
+      id: 'f347e0ac-7614-4643-8fed-e6b5dfb67bcd',
+      metadata: {
+        trusted: false,
+      },
+      outputs: [],
+      source:
+        "a = widgets.FloatText()\nb = widgets.FloatSlider()\ndisplay(a,b)\nlink = widgets.jslink((a, 'value'), (b, 'value'))",
+    },
+    {
+      cell_type: 'code',
+      execution_count: null,
+      id: 'd446f6c2-bf39-498a-8c33-1065ae09688d',
+      metadata: {
+        trusted: false,
+      },
+      outputs: [],
+      source:
+        'import numpy as np\nimport bqplot.pyplot as plt\nsize = 100\nscale = 100.0\nnp.random.seed(0)\nx_data = np.arange(size)\ny_data = np.cumsum(np.random.randn(size) * scale)\nfig = plt.figure(title="First Example")\nplt.plot(y_data)\nfig',
+    },
+    {
+      cell_type: 'code',
+      execution_count: null,
+      id: 'f8210fab',
+      metadata: {
+        trusted: false,
+      },
+      outputs: [],
+      source:
+        'from ipyleaflet import Map, Marker\ncenter = (52.204793, 360.121558)\nm = Map(center=center, zoom=15)\nmarker = Marker(location=center, draggable=True)\nm.add(marker)\nmarker.location = (50, 356)\nm',
+    },
+    {
+      cell_type: 'code',
+      execution_count: null,
+      id: 'e2625839',
+      metadata: {
+        trusted: false,
+      },
+      outputs: [],
+      source:
+        'import ipyreact\nclass ConfettiWidget(ipyreact.ReactWidget):\n    _esm = """\n    import confetti from "canvas-confetti";\n    import * as React from "react";\n\n    export default function({value, set_value, debug}) {\n        return <button onClick={() => confetti() && set_value(value + 1)}>\n            {value || 0} times confetti\n        </button>\n    };"""\nConfettiWidget()',
+    },
+    {
+      cell_type: 'code',
+      execution_count: null,
+      id: 'a5355900',
+      metadata: {
+        trusted: false,
+      },
+      outputs: [],
+      source:
+        'import plotly.express as px\ndf = px.data.stocks()\nfig = px.line(df, x="date", y=df.columns,\n              hover_data={"date": "|%B %d, %Y"},\n              title=\'custom tick labels\')\nfig.update_xaxes(\n    dtick="M1",\n    tickformat="%b %Y",\n    range=["2018-01-01", "2018-12-31"])\nfig.show()',
+    },
+    {
+      cell_type: 'code',
+      execution_count: null,
+      id: '601fee42-f6c2-4d2e-a133-ed8d18faa00f',
+      metadata: {
+        trusted: false,
+      },
+      outputs: [],
+      source:
+        'from matplotlib import pyplot as plt\nimport numpy as np\n%matplotlib widget\nx = np.linspace(0, 1, 100)\ny = 0.2+0.4*x**2+0.3*x*np.sin(15*x)+0.05*np.cos(50*x)\nplt.figure(figsize=(6, 6))\nplt.plot(x, y)',
+    },
+  ],
+  metadata: {
+    kernelspec: {
+      display_name: 'Python 3 (ipykernel)',
+      language: 'python',
+      name: 'python3',
+    },
+    language_info: {
+      codemirror_mode: {
+        name: 'ipython',
+        version: 3,
+      },
+      file_extension: '.py',
+      mimetype: 'text/x-python',
+      name: 'python',
+      nbconvert_exporter: 'python',
+      pygments_lexer: 'ipython3',
+      version: '3.11.4',
+    },
   },
+  nbformat: 4,
+  nbformat_minor: 5,
+};
+
+export const LitePython: Story = Template.bind({});
+LitePython.args = {
+  ...Default.args,
+  browser: 'true',
+  nbformat: WIDGETS_EXAMPLE,
 };
diff --git a/packages/react/webpack.config.js b/packages/react/webpack.config.js
index 9bcebe10..87fe1114 100644
--- a/packages/react/webpack.config.js
+++ b/packages/react/webpack.config.js
@@ -22,30 +22,30 @@ const ENTRY =
   // './src/examples/CellLite';
   // './src/examples/Console';
   './src/examples/ConsoleLite';
-  // './src/examples/Deno';
-  // './src/examples/IPyLeaflet';
-  // './src/examples/IPyReact';
-  // './src/examples/IPyWidgets';
-  // './src/examples/IPyWidgetsWithState';
-  // './src/examples/JupyterLabApp';
-  // './src/examples/JupyterLabHeadlessApp';
-  // './src/examples/Kernels';
-  // './src/examples/KernelExecutor';
-  // './src/examples/KernelExecResult';
-  // './src/examples/Lumino';
-  // './src/examples/Matplotlib';
-  // './src/examples/Notebook';
-  // './src/examples/NotebookColorMode';
-  // './src/examples/NotebookKernelChange';
-  // './src/examples/NotebookLite';
-  // './src/examples/NotebookNbFormat';
-  // './src/examples/NotebookNbFormatChange';
-  // './src/examples/NotebookTheme';
-  // './src/examples/ObservableHQ';
-  // './src/examples/Outputs';
-  // './src/examples/RunningSessions';
-  // './src/examples/Terminal';
-  // './src/examples/Viewer';
+// './src/examples/Deno';
+// './src/examples/IPyLeaflet';
+// './src/examples/IPyReact';
+// './src/examples/IPyWidgets';
+// './src/examples/IPyWidgetsWithState';
+// './src/examples/JupyterLabApp';
+// './src/examples/JupyterLabHeadlessApp';
+// './src/examples/Kernels';
+// './src/examples/KernelExecutor';
+// './src/examples/KernelExecResult';
+// './src/examples/Lumino';
+// './src/examples/Matplotlib';
+// './src/examples/Notebook';
+// './src/examples/NotebookColorMode';
+// './src/examples/NotebookKernelChange';
+// './src/examples/NotebookLite';
+// './src/examples/NotebookNbFormat';
+// './src/examples/NotebookNbFormatChange';
+// './src/examples/NotebookTheme';
+// './src/examples/ObservableHQ';
+// './src/examples/Outputs';
+// './src/examples/RunningSessions';
+// './src/examples/Terminal';
+// './src/examples/Viewer';
 
 const IS_JUPYTER_SERVER_LOCAL = process.env.LOCAL_JUPYTER_SERVER == 'true';
 // const JUPYTER_HOST = IS_JUPYTER_SERVER_LOCAL ? "http://localhost:8686" : "https://oss.datalayer.tech';
@@ -188,7 +188,7 @@ module.exports = {
         generator: {
           filename: 'schema/[name][ext][query]',
         },
-      }
+      },
     ],
   },
   plugins: [
diff --git a/prettier.config.js b/prettier.config.js
index 16c7e512..387195de 100755
--- a/prettier.config.js
+++ b/prettier.config.js
@@ -9,5 +9,6 @@ module.exports = {
 	printWidth: 80,
 	jsxSingleQuote: false,
 	bracketSpacing: true,
-	arrowParens: 'avoid'
+	arrowParens: 'avoid',
+	trailingComma: 'es5'
 };


Test patch:
diff --git a/packages/react/stories/Cell.test.ts b/packages/react/stories/Cell.test.ts
new file mode 100644
index 00000000..8d2714e7
--- /dev/null
+++ b/packages/react/stories/Cell.test.ts
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2021-2023 Datalayer, Inc.
+ *
+ * MIT License
+ */
+
+import { test, expect } from '@playwright/test';
+
+test('Default', async ({ page }) => {
+  await page.goto(
+    'http://localhost:6006/iframe.html?id=components-cell--default'
+  );
+
+  await page.getByLabel('Code Cell Content').waitFor();
+  await page.waitForTimeout(500);
+
+  await page
+    .getByLabel('Code Cell Content')
+    .getByRole('textbox')
+    .fill('print("hello from remote")');
+  await page.keyboard.press('Shift+Enter');
+  await expect(
+    page.getByLabel('Code Cell Content').locator('pre')
+  ).toContainText('hello from remote');
+});
+
+test('Lite Python', async ({ page }) => {
+  await page.goto(
+    'http://localhost:6006/iframe.html?id=components-cell--lite-python'
+  );
+  await page.getByLabel('Code Cell Content with Output').waitFor();
+
+  await expect(
+    page.getByLabel('Code Cell Content with Output').locator('pre')
+  ).toContainText("sys.platform='emscripten'");
+});
diff --git a/packages/react/stories/Console.test.ts b/packages/react/stories/Console.test.ts
index a9307f6e..f8e663d4 100644
--- a/packages/react/stories/Console.test.ts
+++ b/packages/react/stories/Console.test.ts
@@ -15,10 +15,11 @@ test('Default', async ({ page }) => {
   await page
     .getByLabel('Code Cell Content')
     .getByRole('textbox')
+    .last()
     .fill('print("hello from remote")');
   await page.keyboard.press('Shift+Enter');
   await expect(
-    page.getByLabel('notebook content').locator('pre')
+    page.getByLabel('notebook content').locator('pre').last()
   ).toContainText('hello from remote');
 });
 
@@ -33,10 +34,11 @@ test('Lite Python', async ({ page }) => {
   await page
     .getByLabel('Code Cell Content')
     .getByRole('textbox')
+    .last()
     .fill('print("hello from pyodide")');
   await page.keyboard.press('Shift+Enter');
   await expect(
-    page.getByLabel('notebook content').locator('pre')
+    page.getByLabel('notebook content').locator('pre').last()
   ).toContainText('hello from pyodide');
 });
 
@@ -49,9 +51,10 @@ test('Lite JavaScript', async ({ page }) => {
   await page
     .getByLabel('Code Cell Content')
     .getByRole('textbox')
+    .last()
     .fill('Array(4).fill("a")');
   await page.keyboard.press('Shift+Enter');
   await expect(
-    page.getByLabel('notebook content').locator('pre')
+    page.getByLabel('notebook content').locator('pre').last()
   ).toContainText("[ 'a', 'a', 'a', 'a' ]");
 });
diff --git a/packages/react/stories/Notebook.test.ts b/packages/react/stories/Notebook.test.ts
new file mode 100644
index 00000000..c573955f
--- /dev/null
+++ b/packages/react/stories/Notebook.test.ts
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2021-2023 Datalayer, Inc.
+ *
+ * MIT License
+ */
+
+import { test, expect } from '@playwright/test';
+
+test('Default', async ({ page }) => {
+  await page.goto(
+    'http://localhost:6006/iframe.html?id=components-notebook--default'
+  );
+
+  await page
+    .getByRole('region', { name: 'notebook content' })
+    .getByLabel('Code Cell Content')
+    .waitFor();
+  await page.waitForTimeout(500);
+
+  await page
+    .getByLabel('Code Cell Content')
+    .getByRole('textbox')
+    .last()
+    .fill('print("hello from remote")');
+  await page.keyboard.press('Shift+Enter');
+  await expect(
+    page.getByLabel('notebook content').locator('pre').last()
+  ).toContainText('hello from remote');
+});
+
+test('Lite Python', async ({ page }) => {
+  test.setTimeout(60000);
+
+  await page.goto(
+    'http://localhost:6006/iframe.html?id=components-notebook--lite-python'
+  );
+
+  await page.getByText('import piplite').click();
+  await page.keyboard.press('Escape');
+  await page.keyboard.press('Shift+Enter');
+  await page.getByText('[1]:').waitFor();
+
+  await page
+    .getByLabel('Code Cell Content')
+    .getByRole('textbox')
+    .nth(1)
+    .fill('import sys\nprint(f"{sys.platform=}")');
+  await page.keyboard.press('Shift+Enter');
+  await page.getByLabel('Code Cell Content with Output').waitFor();
+
+  await expect(
+    page.getByLabel('Code Cell Content with Output').locator('pre')
+  ).toContainText("sys.platform='emscripten'");
+});