Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions packages/docs-app/src/blueprint.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ Check out the [migration guides to upgrade from v5.x →](https://github.com/
home to over 40 UI components.
Install it with your Node.js package manager of choice:

```sh copy
pnpm add @blueprintjs/core react react-dom
```
@reactDocs InstallSnippet

Additional UI components and APIs are available in:

Expand Down
37 changes: 37 additions & 0 deletions packages/docs-app/src/components/installSnippet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2026 Palantir Technologies, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { CodeToggle, type CodeToggleTab } from "@blueprintjs/docs-theme";

const PACKAGE_MANAGER_PREFERENCE_KEY = "bp-docs-pm-preference";

const INSTALL_TARGET = "@blueprintjs/core react react-dom";

// Append a new entry here to add another package manager (e.g. bun).
const TABS: readonly CodeToggleTab[] = [
{ code: `npm install ${INSTALL_TARGET}`, id: "npm", label: "npm" },
{ code: `yarn add ${INSTALL_TARGET}`, id: "yarn", label: "yarn" },
{ code: `pnpm add ${INSTALL_TARGET}`, id: "pnpm", label: "pnpm" },
];

/**
* Tabbed install snippet showing the same package across the supported
* package managers. The user's choice is persisted across pages so the docs
* remember which client the reader uses.
*/
export const InstallSnippet: React.FC = () => (
<CodeToggle id="install-snippet" tabs={TABS} storageKey={PACKAGE_MANAGER_PREFERENCE_KEY} />
);
4 changes: 1 addition & 3 deletions packages/docs-app/src/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ The JavaScript components are stable and their APIs adhere to [semantic versioni
1. Install the core package and its peer dependencies with an NPM client like `npm` or `pnpm`,
pulling in all relevant dependencies:

```sh copy
pnpm add @blueprintjs/core react react-dom
```
@reactDocs InstallSnippet

2. After installation, you'll be able to import the React components in your application:

Expand Down
1 change: 1 addition & 0 deletions packages/docs-app/src/tags/reactDocs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@
export * from "../components/colorPalettes";
export * from "../components/colorSchemes";
export * from "../components/icons";
export * from "../components/installSnippet";
export * from "../components/welcome";
95 changes: 95 additions & 0 deletions packages/docs-theme/src/components/codeToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* !
* (c) Copyright 2026 Palantir Technologies Inc. All rights reserved.
*/

import { useCallback, useEffect, useMemo, useState } from "react";

import { Code, Pre, Tab, type TabId, Tabs } from "@blueprintjs/core";

export interface CodeToggleTab {
/** Stable identifier used for the tab and the persisted preference. */
id: string;
/** Visible tab label. */
label: string;
/** Code snippet rendered inside `<pre><code>`. */
code: string;
}

export interface CodeToggleProps {
/**
* Tabs to render, in display order. The first tab is selected by default
* when no persisted preference is found.
*/
tabs: readonly CodeToggleTab[];

/**
* Required `id` for the underlying `<Tabs>` element. Must be unique within
* the rendered page.
*/
id: string;

/**
* If provided, the user's selection is persisted in `localStorage` under
* this key and shared across all `CodeToggle` instances using the same key.
* Useful for global preferences like the package manager choice.
*/
storageKey?: string;
}

function readStoredPreference(storageKey: string | undefined, validIds: readonly string[]): string | undefined {
if (storageKey === undefined || typeof window === "undefined") {
return undefined;
}
const stored = window.localStorage.getItem(storageKey);
return stored != null && validIds.includes(stored) ? stored : undefined;
}

/**
* Generic tabbed code-snippet toggle. Each tab renders a `<pre><code>` with
* its corresponding snippet. When `storageKey` is provided, the selection is
* persisted in `localStorage` so the same choice carries across pages.
*/
export const CodeToggle: React.FC<CodeToggleProps> = ({ tabs, id, storageKey }) => {
const validIds = useMemo(() => tabs.map(t => t.id), [tabs]);
const defaultId = tabs[0]?.id ?? "";
const [selected, setSelected] = useState<string>(defaultId);

// Hydrate from localStorage after mount to avoid SSR / first-render mismatches.
useEffect(() => {
const stored = readStoredPreference(storageKey, validIds);
if (stored !== undefined) {
setSelected(stored);
}
}, [storageKey, validIds]);

const handleChange = useCallback(
(newTabId: TabId) => {
const next = String(newTabId);
if (!validIds.includes(next)) {
return;
}
setSelected(next);
if (storageKey !== undefined && typeof window !== "undefined") {
window.localStorage.setItem(storageKey, next);
}
},
[storageKey, validIds],
);

return (
<Tabs id={id} selectedTabId={selected} onChange={handleChange}>
{tabs.map(tab => (
<Tab
key={tab.id}
id={tab.id}
title={tab.label}
panel={
<Pre>
<Code>{tab.code}</Code>
</Pre>
}
/>
))}
</Tabs>
);
};
1 change: 1 addition & 0 deletions packages/docs-theme/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export * from "./components/banner";
export * from "./components/documentation";
export * from "./components/example";
export * from "./components/codeExample";
export * from "./components/codeToggle";
export * from "./components/navMenuItem";
export * from "./components/navButton";
export * from "./common";
Expand Down