diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json
index 986267fe3..a993dea00 100644
--- a/.codesandbox/ci.json
+++ b/.codesandbox/ci.json
@@ -15,6 +15,7 @@
"/packages/docs/sandboxes/fullwidthtab-dockview",
"/packages/docs/sandboxes/groupcontol-dockview",
"/packages/docs/sandboxes/iframe-dockview",
+ "/packages/docs/sandboxes/keyboard-dockview",
"/packages/docs/sandboxes/layout-dockview",
"/packages/docs/sandboxes/lockedgroup-dockview",
"/packages/docs/sandboxes/nativeapp-dockview",
@@ -32,4 +33,4 @@
"/packages/docs/sandboxes/javascript/vanilla-dockview"
],
"node": "16"
-}
+}
\ No newline at end of file
diff --git a/packages/docs/docs/components/dockview.mdx b/packages/docs/docs/components/dockview.mdx
index 25f67edc5..f55a5023e 100644
--- a/packages/docs/docs/components/dockview.mdx
+++ b/packages/docs/docs/components/dockview.mdx
@@ -27,6 +27,7 @@ import DockviewTabheight from '@site/sandboxes/tabheight-dockview/src/app';
import DockviewWithIFrames from '@site/sandboxes/iframe-dockview/src/app';
import DockviewFloating from '@site/sandboxes/floatinggroup-dockview/src/app';
import DockviewLockedGroup from '@site/sandboxes/lockedgroup-dockview/src/app';
+import DockviewKeyboard from '@site/sandboxes/keyboard-dockview/src/app';
import { attach as attachDockviewVanilla } from '@site/sandboxes/javascript/vanilla-dockview/src/app';
import { attach as attachSimpleDockview } from '@site/sandboxes/javascript/simple-dockview/src/app';
@@ -899,7 +900,15 @@ A simple example showing events fired by `dockviewz that can be interacted with.
react={EventsDockview}
/>
-## Advanced Examples
+## Keyboard Navigation
+
+Keyboard shortcuts
+
+
### Nested Dockviews
diff --git a/packages/docs/sandboxes/keyboard-dockview/package.json b/packages/docs/sandboxes/keyboard-dockview/package.json
new file mode 100644
index 000000000..a5766dcba
--- /dev/null
+++ b/packages/docs/sandboxes/keyboard-dockview/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "keyboard-dockview",
+ "description": "",
+ "keywords": [
+ "dockview"
+ ],
+ "version": "1.0.0",
+ "main": "src/index.tsx",
+ "dependencies": {
+ "dockview": "*",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "uuid": "^9.0.0"
+ },
+ "devDependencies": {
+ "@types/react": "^18.0.28",
+ "@types/react-dom": "^18.0.11",
+ "@types/uuid": "^9.0.0",
+ "typescript": "^4.9.5",
+ "react-scripts": "*"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test --env=jsdom",
+ "eject": "react-scripts eject"
+ },
+ "browserslist": [
+ ">0.2%",
+ "not dead",
+ "not ie <= 11",
+ "not op_mini all"
+ ]
+}
diff --git a/packages/docs/sandboxes/keyboard-dockview/public/index.html b/packages/docs/sandboxes/keyboard-dockview/public/index.html
new file mode 100644
index 000000000..5a4850c1d
--- /dev/null
+++ b/packages/docs/sandboxes/keyboard-dockview/public/index.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ React App
+
+
+
+
+
+
+
+
+
diff --git a/packages/docs/sandboxes/keyboard-dockview/src/app.scss b/packages/docs/sandboxes/keyboard-dockview/src/app.scss
new file mode 100644
index 000000000..53fd8f0be
--- /dev/null
+++ b/packages/docs/sandboxes/keyboard-dockview/src/app.scss
@@ -0,0 +1,21 @@
+.keyboard-example-panel {
+ padding: 20px;
+ color: white;
+ font-size: 13px;
+
+ input {
+ &:focus {
+ outline: 1px solid dodgerblue;
+ }
+ }
+
+ .keyboard-example-description {
+ padding: 10px 0px;
+ .keyboard-example-shortcut {
+ background-color: lightblue;
+ color: black;
+ padding: 2px 4px;
+ border-radius: 4px;
+ }
+ }
+}
diff --git a/packages/docs/sandboxes/keyboard-dockview/src/app.tsx b/packages/docs/sandboxes/keyboard-dockview/src/app.tsx
new file mode 100644
index 000000000..021491507
--- /dev/null
+++ b/packages/docs/sandboxes/keyboard-dockview/src/app.tsx
@@ -0,0 +1,137 @@
+import {
+ DockviewApi,
+ DockviewReact,
+ DockviewReadyEvent,
+ IDockviewPanelProps,
+} from 'dockview';
+import './app.scss';
+import * as React from 'react';
+
+const components = {
+ default: (props: IDockviewPanelProps<{ title: string }>) => {
+ const [active, setActive] = React.useState(props.api.isActive);
+ const ref = React.useRef(null);
+
+ React.useEffect(() => {
+ const disposable = props.api.onDidActiveChange((event) => {
+ setActive(props.api.isActive);
+ });
+
+ return () => {
+ disposable.dispose();
+ };
+ }, [props.api]);
+
+ React.useEffect(() => {
+ if (!active) {
+ return;
+ }
+
+ requestAnimationFrame(() => {
+ ref.current?.focus();
+ });
+ }, [active]);
+
+ return (
+
+
+ {props.api.title}
+
+
+ {'Use '}
+
+ {'Ctrl+ArrowLeft'}
+
+ {' and '}
+
+ {'Ctrl+ArrowRight'}
+
+ {' to nativgate between tabs.'}
+
+
+
+
+ {
+ 'This input box should take focus when the panel is active to demonsrate managed focus'
+ }
+
+
+
+
+
+ {'isPanelActive: '}
+ {active ? 'true' : 'false'}
+
+
+ );
+ },
+};
+
+const DockviewDemo = (props: { theme?: string }) => {
+ const [api, setApi] = React.useState();
+
+ const onReady = (event: DockviewReadyEvent) => {
+ event.api.addPanel({
+ id: 'panel_1',
+ component: 'default',
+ title: 'Panel 1',
+ });
+ event.api.addPanel({
+ id: 'panel_2',
+ component: 'default',
+ title: 'Panel 2',
+ });
+ event.api.addPanel({
+ id: 'panel_3',
+ component: 'default',
+ title: 'Panel 3',
+ });
+ event.api.addPanel({
+ id: 'panel_4',
+ component: 'default',
+ title: 'Panel 4',
+ position: { referencePanel: 'panel_3', direction: 'right' },
+ });
+ event.api.addPanel({
+ id: 'panel_5',
+ component: 'default',
+ title: 'Panel 5',
+ position: { referencePanel: 'panel_4', direction: 'within' },
+ });
+
+ event.api.getPanel('panel_1')!.api.setActive();
+
+ setApi(event.api);
+ };
+
+ const onKeyDown = (event: React.KeyboardEvent) => {
+ if (!api) {
+ return;
+ }
+
+ if (event.ctrlKey && event.code === 'ArrowLeft') {
+ // move backwards
+ api.moveToPrevious({ includePanel: true });
+ }
+
+ if (event.ctrlKey && event.code === 'ArrowRight') {
+ // move backwards
+ api.moveToNext({ includePanel: true });
+ }
+ };
+
+ return (
+
+
+
+ );
+};
+
+export default DockviewDemo;
diff --git a/packages/docs/sandboxes/keyboard-dockview/src/index.tsx b/packages/docs/sandboxes/keyboard-dockview/src/index.tsx
new file mode 100644
index 000000000..2fe1be232
--- /dev/null
+++ b/packages/docs/sandboxes/keyboard-dockview/src/index.tsx
@@ -0,0 +1,20 @@
+import { StrictMode } from 'react';
+import * as ReactDOMClient from 'react-dom/client';
+import './styles.css';
+import 'dockview/dist/styles/dockview.css';
+
+import App from './app';
+
+const rootElement = document.getElementById('root');
+
+if (rootElement) {
+ const root = ReactDOMClient.createRoot(rootElement);
+
+ root.render(
+
+
+
+ );
+}
diff --git a/packages/docs/sandboxes/keyboard-dockview/src/styles.css b/packages/docs/sandboxes/keyboard-dockview/src/styles.css
new file mode 100644
index 000000000..92b6a1b36
--- /dev/null
+++ b/packages/docs/sandboxes/keyboard-dockview/src/styles.css
@@ -0,0 +1,16 @@
+body {
+ margin: 0px;
+ color: white;
+ font-family: sans-serif;
+ text-align: center;
+}
+
+#root {
+ height: 100vh;
+ width: 100vw;
+}
+
+.app {
+ height: 100%;
+
+}
diff --git a/packages/docs/sandboxes/keyboard-dockview/tsconfig.json b/packages/docs/sandboxes/keyboard-dockview/tsconfig.json
new file mode 100644
index 000000000..cdc4fb5f5
--- /dev/null
+++ b/packages/docs/sandboxes/keyboard-dockview/tsconfig.json
@@ -0,0 +1,18 @@
+{
+ "compilerOptions": {
+ "outDir": "build/dist",
+ "module": "esnext",
+ "target": "es5",
+ "lib": ["es6", "dom"],
+ "sourceMap": true,
+ "allowJs": true,
+ "jsx": "react-jsx",
+ "moduleResolution": "node",
+ "rootDir": "src",
+ "forceConsistentCasingInFileNames": true,
+ "noImplicitReturns": true,
+ "noImplicitThis": true,
+ "noImplicitAny": true,
+ "strictNullChecks": true
+ }
+}