hide-show-shell
Skill6 starsChanged 8 days agoApache-2.0View on GitHub
MUST be used when a Flows/Fusion app needs full-screen "app-only" mode — hiding the Fusion sidebar and topbar so the app gets the whole viewport, and giving users a clear way to bring the shell back. Triggers: hideShell, full screen app, fullscreen mode, hide sidebar, hide topbar, hide shell, hide menu, setHideShell, app-only mode, kiosk mode, custom side nav, full viewport.
In this repository34 other files it gives its agents.
- aura-reviewSkill
- call-cognite-functionSkill
- code-qualitySkill
- connect-atlas-mcpSkill
- correctness-and-error-handlingSkill
- create-agentSkill
- create-client-toolSkill
- dependencies-auditSkill
- designSkill
- dm-graph-traversalSkill
- dm-limits-and-best-practicesSkill
- flows-app-briefSkill
- flows-code-reviewSkill
- flows-design-reviewSkill
- flows-external-app-submitSkill
- flows-review-checksSkill
- graph-viewerSkill
- handle-startup-stateSkill
- integrate-atlas-chatSkill
- integrate-file-viewerSkill
- integrate-fusion-agentSkill
- integrate-todo-listSkill
- migrate-app-to-flowsSkill
- performanceSkill
- pull-changes-resolve-conflictsSkill
- reveal-3dSkill
- securitySkill
- setup-flows-authSkill
- setup-python-toolsSkill
- skill-creatorSkill
- start-flows-appSkill
- test-coverageSkill
- tygenSkill
- use-topbarSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 89
Create (or add to an existing hooks file) src/hooks/use-hide-shell.ts.
- Very specific: line 151
Place <FullScreenToggle api={api} /> wherever your best-practice placement (above) calls for it — bottom of your custom nav, or a fixed …
- Very specific: line 166
Add tests alongside the hook at src/hooks/use-hide-shell.test.ts:
- Distinctive: line 239
Don't build extra fallback UI for the "flag off" case — the call is a no-op and the shell simply stays visible.
- Very specific: line 255
If your own side nav needs to visually line up with (or replace) the CDF sidebar, match these widths from apps/navigation's navrail …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Hide & Show the Fusion Shell
Lets a Flows app hide the Fusion sidebar + topbar (the "shell") to use the full browser viewport, and reveal it again — without leaving the user stranded.
Requires @cognite/app-sdk's connectToHostApp() handshake already wired
up, and @cognite/app-sdk >= 0.9.0 (verify with npm ls @cognite/app-sdk
or check package.json — earlier versions don't expose setHideShell on
HostAppAPI at all). If auth isn't wired up yet, run the
setup-flows-auth skill first — but make sure
it lands on the Apps API flow (app.json has "infra": "appsApi",
deployed with npx @cognite/cli@latest apps deploy), not the Classic
flow (DuneAuthProvider/useDune() from @cognite/dune). setHideShell
only exists on the Apps API's HostAppAPI; Classic apps have no equivalent
and are deployed to infrastructure @cognite/cli itself refuses to touch
("Legacy infrastructure is no longer supported"). If app.json is missing
infra: "appsApi" or @cognite/dune shows up in package.json, stop and
migrate to Apps API first — don't attempt this skill on a Classic app.
What it does
HostAppAPI.setHideShell(hidden: boolean): Promise<void> (from the api
object returned by connectToHostApp()):
setHideShell(true)— hides the CDF sidebar and topbar, giving the app the full viewport.setHideShell(false)— reveals them again.
Under the hood this toggles a bookmarkable ?hideShell=true URL parameter —
no server round-trip, and a shared link already opens in full-screen mode.
The shell also auto-reveals if the user navigates away from your app, as
a safety net — but don't rely on that as your only way back.
There is no other safety net. While the shell is hidden, Fusion does not render any floating "reveal" button of its own — the navrail (and any toggle button inside it) is unmounted along with the rest of the shell. The only ways back are: your app's own reveal control, manually editing the URL, or navigating away entirely. Treat the guidance below as non-negotiable, not a nice-to-have.
When to use it
Good fit:
- Your app renders its own side navigation, so the CDF sidebar is redundant screen real estate.
- The app needs the full canvas — a dashboard, drawing surface, kiosk-style view, etc.
Not a fit:
- Hiding the shell "by default" with no user action — always gate it behind an explicit, reversible interaction (a toggle the user clicks), never on mount.
Non-negotiable: always leave a way back
The #1 failure mode of this feature is trapping the user in full-screen with
no visible way to get the CDF navigation back. Every setHideShell(true)
call must ship with an equally discoverable reveal control:
- App has its own side nav — put a small "Show Cognite menu" control at the bottom of that nav, in the same spot the CDF sidebar's own collapse/expand toggle would be. This is the pattern the platform team converged on for Flows apps.
- App has no side nav — use a persistent, low-key icon button (e.g. fixed corner) that's always visible, not something that only appears on hover. Hover-only affordances don't work on touch/mobile.
- Icon-only toggles need an
aria-label(e.g."Hide Cognite menu"/"Show Cognite menu") — don't ship an icon button screen readers can't interpret. A button with visible label text already has an accessible name and doesn't need one.
Step 1 — Add the useHideShell hook
Create (or add to an existing hooks file) src/hooks/use-hide-shell.ts. This
centralizes the toggle logic and — critically — restores the shell on
unmount, so navigating within your own app (or an error boundary tearing
down the tree) can never leave the shell permanently hidden:
import { useCallback, useEffect, useState } from 'react';
import type { HostAppAPI } from '@cognite/app-sdk';
/**
* Manages Fusion shell visibility for full-screen "app-only" mode.
*
* Restores the shell automatically on unmount so it's never left hidden
* if the user navigates away or the component tears down unexpectedly.
*/
export function useHideShell(api: HostAppAPI | null) {
const [isHidden, setIsHidden] = useState(false);
const setHidden = useCallback(
async (next: boolean) => {
if (!api) return;
await api.setHideShell(next);
setIsHidden(next);
},
[api],
);
const toggle = useCallback(() => setHidden(!isHidden), [setHidden, isHidden]);
const hide = useCallback(() => setHidden(true), [setHidden]);
const reveal = useCallback(() => setHidden(false), [setHidden]);
useEffect(() => {
return () => {
if (isHidden && api) void api.setHideShell(false);
};
}, [api, isHidden]);
return { isHidden, toggle, hide, reveal };
}Step 2 — Add the toggle control
import type { HostAppAPI } from '@cognite/app-sdk';
import { Button } from '@cognite/aura/components';
import { IconEye, IconEyeOff } from '@tabler/icons-react';
import { useHideShell } from '../hooks/use-hide-shell';
function FullScreenToggle({ api }: { api: HostAppAPI | null }) {
const { isHidden, toggle } = useHideShell(api);
return (
<Button variant="secondary" size="sm" onClick={toggle} disabled={!api}>
{isHidden ? <IconEye aria-hidden /> : <IconEyeOff aria-hidden />}
{isHidden ? 'Show Cognite menu' : 'Hide Cognite menu'}
</Button>
);
}Place <FullScreenToggle api={api} /> wherever your best-practice placement
(above) calls for it — bottom of your custom nav, or a fixed corner control.
IconEye/IconEyeOff read more clearly as a visibility toggle than
arrows-style icons, which are easily confused with the separate native
Fullscreen API. This matches the icon choice used in a working, deployed
reference app for this skill (IconEyeOff to hide, IconEye to reveal).
Buttoncomes from the@cognite/aura/componentssubpath — the package only exports that path (plus./utils,./eslint,./styles.css), not a per-component@cognite/aura/components/buttonpath. Importing the latter throwsERR_PACKAGE_PATH_NOT_EXPORTEDat build time.
Step 3 — Add tests
Add tests alongside the hook at src/hooks/use-hide-shell.test.ts:
import { act, renderHook } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { HostAppAPI } from '@cognite/app-sdk';
import { useHideShell } from './use-hide-shell';
function makeApi(): Pick<HostAppAPI, 'setHideShell'> {
return { setHideShell: vi.fn(() => Promise.resolve()) };
}
describe('useHideShell', () => {
let api: ReturnType<typeof makeApi>;
beforeEach(() => {
api = makeApi();
vi.clearAllMocks();
});
it('starts with the shell visible', () => {
const { result } = renderHook(() => useHideShell(api as HostAppAPI));
expect(result.current.isHidden).toBe(false);
});
it('hides the shell on toggle', async () => {
const { result } = renderHook(() => useHideShell(api as HostAppAPI));
await act(() => result.current.toggle());
expect(api.setHideShell).toHaveBeenCalledWith(true);
expect(result.current.isHidden).toBe(true);
});
it('reveals the shell on the second toggle', async () => {
const { result } = renderHook(() => useHideShell(api as HostAppAPI));
await act(() => result.current.toggle());
await act(() => result.current.toggle());
expect(api.setHideShell).toHaveBeenLastCalledWith(false);
expect(result.current.isHidden).toBe(false);
});
it('restores the shell on unmount when hidden', async () => {
const { result, unmount } = renderHook(() => useHideShell(api as HostAppAPI));
await act(() => result.current.hide());
unmount();
expect(api.setHideShell).toHaveBeenLastCalledWith(false);
});
it('does not call setHideShell on unmount when already visible', () => {
const { unmount } = renderHook(() => useHideShell(api as HostAppAPI));
unmount();
expect(api.setHideShell).not.toHaveBeenCalled();
});
it('is a no-op when api is null (running outside Fusion)', async () => {
const { result } = renderHook(() => useHideShell(null));
await act(() => result.current.toggle());
expect(result.current.isHidden).toBe(false);
});
});Step 4 — Handle the case where the shell doesn't hide
Three conditions must all be true for setHideShell(true) to actually
hide anything:
- The
NAVIGATION_HIDE_SHELLUnleash flag is enabled for the environment. - Your app is the active route the shell recognizes as a managed Flows app
(the Custom Apps subapp, with
?hideShellpresent in the URL). - Nothing else on the page has already re-shown the shell (e.g. the user navigated to a different Fusion area, which auto-reveals it).
Don't build extra fallback UI for the "flag off" case — the call is a no-op and the shell simply stays visible. Just don't assume the toggle always visibly does something in every environment while testing.
Step 5 — Test both directions
- Click "Hide Cognite menu" → shell disappears, app fills the viewport, the
URL now has
?hideShell=true. - Click "Show Cognite menu" → shell reappears,
hideShellis removed from the URL. - Reload the page with
?hideShell=truein the URL → shell starts hidden (bookmarkable). - Navigate to an unrelated Fusion route while hidden → shell auto-reveals.
Matching the Fusion sidebar's width
If your own side nav needs to visually line up with (or replace) the CDF
sidebar, match these widths from apps/navigation's navrail
(apps/navigation/src/utils/constants.ts in cognitedata/fusion):
| State | Width |
| Expanded | min-width: 240px, max-width: 280px (actual width is content-driven, capped to that range) |
| Collapsed | 56px |
These are internal implementation details of the Fusion shell, not a public design-system token — re-check them if the sidebar's look changes noticeably, since there's no guarantee they stay in sync with this skill.
Related
- setup-flows-auth — prerequisite
app-sdkconnection. - use-topbar — if your app renders its own topbar, the shell toggle above is unrelated to (and composes fine with) that in-app Aura Topbar.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

