Product interfaces · Original
Product bento
A light product bento with activity, people, integrations, and shortcut interfaces that change by tab.
Live preview
Try it in context
Customize preview
Source delivery
v0.3.0Usage & source
"use client";
import type { CSSProperties } from "react";
import { ProductBento } from "./components/stepkit/ProductBento";
import "./components/stepkit/styles.css";
import "./components/stepkit/showcase.css";
const themeStyle = {"--stepkit-bg":"#f7f7f8","--stepkit-surface":"#ffffff","--stepkit-surface-muted":"#f0f0f3","--stepkit-fg":"#17181c","--stepkit-muted":"#626572","--stepkit-border":"#e3e4e9","--stepkit-border-strong":"#c8cad3","--stepkit-code":"#f1f1f4","--stepkit-shadow":"0 20px 60px rgba(31, 26, 64, .10)","--stepkit-accent":"#2563eb","--stepkit-accent-strong":"#1d4ed8","--stepkit-accent-soft":"#e8efff","--stepkit-accent-on-soft":"#1d4ed8","--stepkit-accent-text":"#ffffff","--stepkit-error":"#b43145","--stepkit-placeholder":"#626572","--stepkit-radius":"16px","--stepkit-space":"16px","--stepkit-control-height":"44px","--stepkit-font-sans":"Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif"} as CSSProperties;
export default function Example() {
return (
<div className="stepkit-theme" data-stepkit-preset="modern" style={themeStyle}>
<ProductBento
defaultActivePanel={"overview"}
/>
</div>
);
}Dependencies
[email protected] [email protected]
/*
* Stepkit 0.3.0
* Copyright (c) 2026 Vladislav Stepanov
*
* Original Stepkit portions in this release are licensed under the MIT License. Adapted portions identify their upstream licence and attribution in the copied source and in the entry-specific upstream notice files.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
"use client";
import { useId, useState } from "react";
import "./styles.css";
import "./showcase.css";
export type ProductBentoPanel = "overview" | "integrations" | "shortcuts";
export interface ProductBentoProps {
activePanel?: ProductBentoPanel;
defaultActivePanel?: ProductBentoPanel;
onPanelChange?: (panel: ProductBentoPanel) => void;
title?: string;
description?: string;
className?: string;
}
const panels: Array<{ id: ProductBentoPanel; label: string }> = [
{ id: "overview", label: "Overview" },
{ id: "integrations", label: "Integrations" },
{ id: "shortcuts", label: "Shortcuts" }
];
export function ProductBento({ activePanel, defaultActivePanel = "overview", onPanelChange, title = "Your work, in the right places.", description = "A product surface built from small, believable interfaces that keep their hierarchy.", className = "" }: ProductBentoProps) {
const headingId = useId();
const [internalPanel, setInternalPanel] = useState<ProductBentoPanel>(defaultActivePanel);
const selectedPanel = activePanel ?? internalPanel;
const selectPanel = (panel: ProductBentoPanel) => { if (activePanel === undefined) setInternalPanel(panel); onPanelChange?.(panel); };
const panelCopy = selectedPanel === "integrations" ? "Four connected surfaces are keeping the workspace in sync." : selectedPanel === "shortcuts" ? "The fastest paths are close enough to become habits." : "A quiet view of what moved forward this week.";
return <section className={`stepkit stepkit-showcase stepkit-product-bento${className ? ` ${className}` : ""}`} data-panel={selectedPanel} aria-labelledby={headingId}>
<header className="stepkit-product-bento__header"><div><span className="stepkit-product-bento__eyebrow">Product bento / workspace view</span><h2 className="stepkit-product-bento__title" id={headingId}>{title}</h2><p className="stepkit-product-bento__description">{description}</p></div><div className="stepkit-product-bento__tabs" aria-label="Product views">{panels.map((panel) => <button className="stepkit-product-bento__tab" type="button" aria-pressed={selectedPanel === panel.id} key={panel.id} onClick={() => selectPanel(panel.id)}>{panel.label}</button>)}</div></header>
<p className="stepkit-sr-only" aria-live="polite">{panelCopy}</p>
<div className="stepkit-product-bento__grid">
<article className="stepkit-product-bento__tile stepkit-product-bento__tile--activity"><span className="stepkit-product-bento__tile-label">Activity / 7 days</span><h3 className="stepkit-product-bento__tile-title">Momentum is building</h3><div className="stepkit-product-bento__chart" aria-label="Activity bars"><span className="stepkit-product-bento__bar" style={{ height: "43%" }} /><span className="stepkit-product-bento__bar" style={{ height: "67%" }} /><span className="stepkit-product-bento__bar" style={{ height: "52%" }} /><span className="stepkit-product-bento__bar" style={{ height: "77%" }} /><span className="stepkit-product-bento__bar" style={{ height: "88%" }} /><span className="stepkit-product-bento__bar" style={{ height: "71%" }} /><span className="stepkit-product-bento__bar" style={{ height: "95%" }} /></div><span className="stepkit-product-bento__chart-axis" aria-hidden="true" /><p className="stepkit-product-bento__summary">{selectedPanel === "overview" ? "28 completed actions · +12% this week" : selectedPanel === "integrations" ? "14 updates arrived from connected tools" : "9 shortcuts used more than once today"}</p></article>
<article className={`stepkit-product-bento__tile stepkit-product-bento__tile--team${selectedPanel === "overview" ? " is-selected" : ""}`}><span className="stepkit-product-bento__tile-label">Team pulse</span><h3 className="stepkit-product-bento__tile-title">People in the loop</h3><div className="stepkit-product-bento__avatars" aria-label="Four team members"><span className="stepkit-product-bento__avatar">AR</span><span className="stepkit-product-bento__avatar">NC</span><span className="stepkit-product-bento__avatar">MO</span><span className="stepkit-product-bento__avatar">+4</span></div><p className="stepkit-product-bento__summary">7 active contributors</p></article>
<article className={`stepkit-product-bento__tile stepkit-product-bento__tile--integration${selectedPanel === "integrations" ? " is-selected" : ""}`}><span className="stepkit-product-bento__tile-label">Connected / live</span><h3 className="stepkit-product-bento__tile-title">Everything in orbit</h3><div className="stepkit-product-bento__orbit" aria-hidden="true"><span className="stepkit-product-bento__orbit-core">hub</span><span className="stepkit-product-bento__orbit-node">fig</span><span className="stepkit-product-bento__orbit-node">git</span><span className="stepkit-product-bento__orbit-node">slk</span></div></article>
<article className={`stepkit-product-bento__tile stepkit-product-bento__tile--shortcuts${selectedPanel === "shortcuts" ? " is-selected" : ""}`}><span className="stepkit-product-bento__tile-label">Quick actions</span><h3 className="stepkit-product-bento__tile-title">Make it a habit</h3><div className="stepkit-product-bento__shortcuts"><span className="stepkit-product-bento__shortcut">New workspace <kbd>⌘ N</kbd></span><span className="stepkit-product-bento__shortcut">Open command menu <kbd>⌘ K</kbd></span><span className="stepkit-product-bento__shortcut">Share update <kbd>⌘ ↵</kbd></span></div></article>
</div>
</section>;
}
export default ProductBento;
components/ProductBento.tsxcomponents/showcase.csscomponents/styles.cssInstall
Use the registry command or download the complete source archive.
npx [email protected] add https://vstepanov.com/stepkit/r/product-bento.jsonIntegration prompt
Install Stepkit Product bento 0.3.0 from the registry and preserve the included MIT notice. npx [email protected] add https://vstepanov.com/stepkit/v0.3.0/r/product-bento.json Install the tested runtime dependencies exactly: npm install [email protected] [email protected] Keep the component source, shared styles, NOTICE.md, and provenance files together. Apply the theme tokens on a wrapper rather than passing theme keys as component props. Usage: ```tsx "use client"; import type { CSSProperties } from "react"; import { ProductBento } from "./components/stepkit/ProductBento"; import "./components/stepkit/styles.css"; import "./components/stepkit/showcase.css"; const themeStyle = {"--stepkit-bg":"#f7f7f8","--stepkit-surface":"#ffffff","--stepkit-surface-muted":"#f0f0f3","--stepkit-fg":"#17181c","--stepkit-muted":"#626572","--stepkit-border":"#e3e4e9","--stepkit-border-strong":"#c8cad3","--stepkit-code":"#f1f1f4","--stepkit-shadow":"0 20px 60px rgba(31, 26, 64, .10)","--stepkit-accent":"#6950df","--stepkit-accent-strong":"#5137c7","--stepkit-accent-soft":"#eeeafd","--stepkit-accent-on-soft":"#5137c7","--stepkit-accent-text":"#ffffff","--stepkit-error":"#b43145","--stepkit-placeholder":"#626572","--stepkit-radius":"16px","--stepkit-space":"16px","--stepkit-control-height":"44px","--stepkit-font-sans":"Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif"} as CSSProperties; export default function Example() { return ( <div className="stepkit-theme" data-stepkit-preset="modern" style={themeStyle}> <ProductBento defaultActivePanel={"overview"} /> </div> ); } ``` Selected bounded settings: {"defaultActivePanel":"overview"}. Selected theme: {"mode":"light","accent":"violet","radius":"soft","density":"comfortable","preset":"modern"}.
Props
| Name | Type | Default | Description |
|---|---|---|---|
activePanel | "overview" | "integrations" | "shortcuts" | undefined | Controlled active product panel. |
defaultActivePanel | "overview" | "integrations" | "shortcuts" | "overview" | Initial panel. |
onPanelChange | (panel: ProductBentoPanel) => void | undefined | Called after a tab change. |
title | string | "Your work, in the right places." | Bento heading. |
Accessibility & limits
- Tabs expose selected state and the active product context is announced.
- Charts and interface tiles pair colour with readable labels.
- All panel changes are native button interactions.
Limitations
- The built-in metrics and names are illustrative product UI content; replace them for production use.
Provenance
Original source under the MIT licence.
Original Stepkit implementation.
Required notices: NOTICE.md, PROVENANCE-stepkit-product-bento.md