The Framer example is a split-panel component browser. The left column lists component items; the right column renders a live preview of whichever item is currently selected. Selecting a new item instantly swaps the preview — no modal, no navigation — making the palette feel like an interactive component picker rather than a traditional command menu. The selection highlight uses Framer’s blue accent color (Documentation Index
Fetch the complete documentation index at: https://mintlify.com/dip/cmdk/llms.txt
Use this file to discover all available pages before exploring further.
var(--blue9)) and turns the item text white, maintaining high contrast without any additional state.
- Component
- Stylesheet
import { Command } from 'cmdk'
import React from 'react'
export function FramerCMDK() {
const [value, setValue] = React.useState('Button')
return (
<div className="framer">
<Command value={value} onValueChange={(v) => setValue(v)}>
<div cmdk-framer-header="">
<SearchIcon />
<Command.Input autoFocus placeholder="Find components, packages, and interactions..." />
</div>
<Command.List>
<div cmdk-framer-items="">
<div cmdk-framer-left="">
<Command.Group heading="Components">
<Item value="Button" subtitle="Trigger actions">
<ButtonIcon />
</Item>
<Item value="Input" subtitle="Retrieve user input">
<InputIcon />
</Item>
<Item value="Radio" subtitle="Single choice input">
<RadioIcon />
</Item>
<Item value="Badge" subtitle="Annotate context">
<BadgeIcon />
</Item>
<Item value="Slider" subtitle="Free range picker">
<SliderIcon />
</Item>
<Item value="Avatar" subtitle="Illustrate the user">
<AvatarIcon />
</Item>
<Item value="Container" subtitle="Lay out items">
<ContainerIcon />
</Item>
</Command.Group>
</div>
<hr cmdk-framer-separator="" />
<div cmdk-framer-right="">
{value === 'Button' && <Button />}
{value === 'Input' && <Input />}
{value === 'Badge' && <Badge />}
{value === 'Radio' && <Radio />}
{value === 'Avatar' && <Avatar />}
{value === 'Slider' && <Slider />}
{value === 'Container' && <Container />}
</div>
</div>
</Command.List>
</Command>
</div>
)
}
function Button() {
return <button>Primary</button>
}
function Input() {
return <input type="text" placeholder="Placeholder" />
}
function Badge() {
return <div cmdk-framer-badge="">Badge</div>
}
function Radio() {
return (
<label cmdk-framer-radio="">
<input type="radio" defaultChecked />
Radio Button
</label>
)
}
function Slider() {
return (
<div cmdk-framer-slider="">
<div />
</div>
)
}
function Avatar() {
return <img src="/rauno.jpeg" alt="Avatar of Rauno" />
}
function Container() {
return <div cmdk-framer-container="" />
}
function Item({ children, value, subtitle }: { children: React.ReactNode; value: string; subtitle: string }) {
return (
<Command.Item value={value} onSelect={() => {}}>
<div cmdk-framer-icon-wrapper="">{children}</div>
<div cmdk-framer-item-meta="">
{value}
<span cmdk-framer-item-subtitle="">{subtitle}</span>
</div>
</Command.Item>
)
}
function ButtonIcon() {
return (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M2 5H13C13.5523 5 14 5.44772 14 6V9C14 9.55228 13.5523 10 13 10H2C1.44772 10 1 9.55228 1 9V6C1 5.44772 1.44772 5 2 5ZM0 6C0 4.89543 0.895431 4 2 4H13C14.1046 4 15 4.89543 15 6V9C15 10.1046 14.1046 11 13 11H2C0.89543 11 0 10.1046 0 9V6ZM4.5 6.75C4.08579 6.75 3.75 7.08579 3.75 7.5C3.75 7.91421 4.08579 8.25 4.5 8.25C4.91421 8.25 5.25 7.91421 5.25 7.5C5.25 7.08579 4.91421 6.75 4.5 6.75ZM6.75 7.5C6.75 7.08579 7.08579 6.75 7.5 6.75C7.91421 6.75 8.25 7.08579 8.25 7.5C8.25 7.91421 7.91421 8.25 7.5 8.25C7.08579 8.25 6.75 7.91421 6.75 7.5ZM10.5 6.75C10.0858 6.75 9.75 7.08579 9.75 7.5C9.75 7.91421 10.0858 8.25 10.5 8.25C10.9142 8.25 11.25 7.91421 11.25 7.5C11.25 7.08579 10.9142 6.75 10.5 6.75Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
)
}
function InputIcon() {
return (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M6.5 1C6.22386 1 6 1.22386 6 1.5C6 1.77614 6.22386 2 6.5 2C7.12671 2 7.45718 2.20028 7.65563 2.47812C7.8781 2.78957 8 3.28837 8 4V11C8 11.7116 7.8781 12.2104 7.65563 12.5219C7.45718 12.7997 7.12671 13 6.5 13C6.22386 13 6 13.2239 6 13.5C6 13.7761 6.22386 14 6.5 14C7.37329 14 8.04282 13.7003 8.46937 13.1031C8.47976 13.0886 8.48997 13.0739 8.5 13.0591C8.51003 13.0739 8.52024 13.0886 8.53063 13.1031C8.95718 13.7003 9.62671 14 10.5 14C10.7761 14 11 13.7761 11 13.5C11 13.2239 10.7761 13 10.5 13C9.87329 13 9.54282 12.7997 9.34437 12.5219C9.1219 12.2104 9 11.7116 9 11V4C9 3.28837 9.1219 2.78957 9.34437 2.47812C9.54282 2.20028 9.87329 2 10.5 2C10.7761 2 11 1.77614 11 1.5C11 1.22386 10.7761 1 10.5 1C9.62671 1 8.95718 1.29972 8.53063 1.89688C8.52024 1.91143 8.51003 1.92611 8.5 1.9409C8.48997 1.92611 8.47976 1.91143 8.46937 1.89688C8.04282 1.29972 7.37329 1 6.5 1ZM14 5H11V4H14C14.5523 4 15 4.44772 15 5V10C15 10.5523 14.5523 11 14 11H11V10H14V5ZM6 4V5H1L1 10H6V11H1C0.447715 11 0 10.5523 0 10V5C0 4.44772 0.447715 4 1 4H6Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
)
}
function RadioIcon() {
return (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M7.49985 0.877045C3.84216 0.877045 0.877014 3.84219 0.877014 7.49988C0.877014 11.1575 3.84216 14.1227 7.49985 14.1227C11.1575 14.1227 14.1227 11.1575 14.1227 7.49988C14.1227 3.84219 11.1575 0.877045 7.49985 0.877045ZM1.82701 7.49988C1.82701 4.36686 4.36683 1.82704 7.49985 1.82704C10.6328 1.82704 13.1727 4.36686 13.1727 7.49988C13.1727 10.6329 10.6328 13.1727 7.49985 13.1727C4.36683 13.1727 1.82701 10.6329 1.82701 7.49988ZM7.49999 9.49999C8.60456 9.49999 9.49999 8.60456 9.49999 7.49999C9.49999 6.39542 8.60456 5.49999 7.49999 5.49999C6.39542 5.49999 5.49999 6.39542 5.49999 7.49999C5.49999 8.60456 6.39542 9.49999 7.49999 9.49999Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
)
}
function BadgeIcon() {
return (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M3.5 6H11.5C12.3284 6 13 6.67157 13 7.5C13 8.32843 12.3284 9 11.5 9H3.5C2.67157 9 2 8.32843 2 7.5C2 6.67157 2.67157 6 3.5 6ZM1 7.5C1 6.11929 2.11929 5 3.5 5H11.5C12.8807 5 14 6.11929 14 7.5C14 8.88071 12.8807 10 11.5 10H3.5C2.11929 10 1 8.88071 1 7.5ZM4.5 7C4.22386 7 4 7.22386 4 7.5C4 7.77614 4.22386 8 4.5 8H10.5C10.7761 8 11 7.77614 11 7.5C11 7.22386 10.7761 7 10.5 7H4.5Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
)
}
function ToggleIcon() {
return (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M10.5 4C8.567 4 7 5.567 7 7.5C7 9.433 8.567 11 10.5 11C12.433 11 14 9.433 14 7.5C14 5.567 12.433 4 10.5 4ZM7.67133 11C6.65183 10.175 6 8.91363 6 7.5C6 6.08637 6.65183 4.82498 7.67133 4H4.5C2.567 4 1 5.567 1 7.5C1 9.433 2.567 11 4.5 11H7.67133ZM0 7.5C0 5.01472 2.01472 3 4.5 3H10.5C12.9853 3 15 5.01472 15 7.5C15 9.98528 12.9853 12 10.5 12H4.5C2.01472 12 0 9.98528 0 7.5Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
)
}
function AvatarIcon() {
return (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M0.877014 7.49988C0.877014 3.84219 3.84216 0.877045 7.49985 0.877045C11.1575 0.877045 14.1227 3.84219 14.1227 7.49988C14.1227 11.1575 11.1575 14.1227 7.49985 14.1227C3.84216 14.1227 0.877014 11.1575 0.877014 7.49988ZM7.49985 1.82704C4.36683 1.82704 1.82701 4.36686 1.82701 7.49988C1.82701 8.97196 2.38774 10.3131 3.30727 11.3213C4.19074 9.94119 5.73818 9.02499 7.50023 9.02499C9.26206 9.02499 10.8093 9.94097 11.6929 11.3208C12.6121 10.3127 13.1727 8.97172 13.1727 7.49988C13.1727 4.36686 10.6328 1.82704 7.49985 1.82704ZM10.9818 11.9787C10.2839 10.7795 8.9857 9.97499 7.50023 9.97499C6.01458 9.97499 4.71624 10.7797 4.01845 11.9791C4.97952 12.7272 6.18765 13.1727 7.49985 13.1727C8.81227 13.1727 10.0206 12.727 10.9818 11.9787ZM5.14999 6.50487C5.14999 5.207 6.20212 4.15487 7.49999 4.15487C8.79786 4.15487 9.84999 5.207 9.84999 6.50487C9.84999 7.80274 8.79786 8.85487 7.49999 8.85487C6.20212 8.85487 5.14999 7.80274 5.14999 6.50487ZM7.49999 5.10487C6.72679 5.10487 6.09999 5.73167 6.09999 6.50487C6.09999 7.27807 6.72679 7.90487 7.49999 7.90487C8.27319 7.90487 8.89999 7.27807 8.89999 6.50487C8.89999 5.73167 8.27319 5.10487 7.49999 5.10487Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
)
}
function ContainerIcon() {
return (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M2 1.5C2 1.77614 1.77614 2 1.5 2C1.22386 2 1 1.77614 1 1.5C1 1.22386 1.22386 1 1.5 1C1.77614 1 2 1.22386 2 1.5ZM5 13H10V2L5 2L5 13ZM4 13C4 13.5523 4.44772 14 5 14H10C10.5523 14 11 13.5523 11 13V2C11 1.44772 10.5523 1 10 1H5C4.44772 1 4 1.44771 4 2V13ZM13.5 2C13.7761 2 14 1.77614 14 1.5C14 1.22386 13.7761 1 13.5 1C13.2239 1 13 1.22386 13 1.5C13 1.77614 13.2239 2 13.5 2ZM2 3.5C2 3.77614 1.77614 4 1.5 4C1.22386 4 1 3.77614 1 3.5C1 3.22386 1.22386 3 1.5 3C1.77614 3 2 3.22386 2 3.5ZM13.5 4C13.7761 4 14 3.77614 14 3.5C14 3.22386 13.7761 3 13.5 3C13.2239 3 13 3.22386 13 3.5C13 3.77614 13.2239 4 13.5 4ZM2 5.5C2 5.77614 1.77614 6 1.5 6C1.22386 6 1 5.77614 1 5.5C1 5.22386 1.22386 5 1.5 5C1.77614 5 2 5.22386 2 5.5ZM13.5 6C13.7761 6 14 5.77614 14 5.5C14 5.22386 13.7761 5 13.5 5C13.2239 5 13 5.22386 13 5.5C13 5.77614 13.2239 6 13.5 6ZM2 7.5C2 7.77614 1.77614 8 1.5 8C1.22386 8 1 7.77614 1 7.5C1 7.22386 1.22386 7 1.5 7C1.77614 7 2 7.22386 2 7.5ZM13.5 8C13.7761 8 14 7.77614 14 7.5C14 7.22386 13.7761 7 13.5 7C13.2239 7 13 7.22386 13 7.5C13 7.77614 13.2239 8 13.5 8ZM2 9.5C2 9.77614 1.77614 10 1.5 10C1.22386 10 1 9.77614 1 9.5C1 9.22386 1.22386 9 1.5 9C1.77614 9 2 9.22386 2 9.5ZM13.5 10C13.7761 10 14 9.77614 14 9.5C14 9.22386 13.7761 9 13.5 9C13.2239 9 13 9.22386 13 9.5C13 9.77614 13.2239 10 13.5 10ZM2 11.5C2 11.7761 1.77614 12 1.5 12C1.22386 12 1 11.7761 1 11.5C1 11.2239 1.22386 11 1.5 11C1.77614 11 2 11.2239 2 11.5ZM13.5 12C13.7761 12 14 11.7761 14 11.5C14 11.2239 13.7761 11 13.5 11C13.2239 11 13 11.2239 13 11.5C13 11.7761 13.2239 12 13.5 12ZM2 13.5C2 13.7761 1.77614 14 1.5 14C1.22386 14 1 13.7761 1 13.5C1 13.2239 1.22386 13 1.5 13C1.77614 13 2 13.2239 2 13.5ZM13.5 14C13.7761 14 14 13.7761 14 13.5C14 13.2239 13.7761 13 13.5 13C13.2239 13 13 13.2239 13 13.5C13 13.7761 13.2239 14 13.5 14Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
)
}
function SearchIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={1.5}
>
<path strokeLinecap="round" strokeLinejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
)
}
function SliderIcon() {
return (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M10.3004 7.49991C10.3004 8.4943 9.49426 9.30041 8.49988 9.30041C7.50549 9.30041 6.69938 8.4943 6.69938 7.49991C6.69938 6.50553 7.50549 5.69942 8.49988 5.69942C9.49426 5.69942 10.3004 6.50553 10.3004 7.49991ZM11.205 8C10.9699 9.28029 9.84816 10.2504 8.49988 10.2504C7.1516 10.2504 6.0299 9.28029 5.79473 8H0.5C0.223858 8 0 7.77614 0 7.5C0 7.22386 0.223858 7 0.5 7H5.7947C6.0298 5.71962 7.15154 4.74942 8.49988 4.74942C9.84822 4.74942 10.97 5.71962 11.2051 7H14.5C14.7761 7 15 7.22386 15 7.5C15 7.77614 14.7761 8 14.5 8H11.205Z"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
></path>
</svg>
)
}
.framer {
[cmdk-root] {
max-width: 640px;
width: 100%;
padding: 8px;
background: #ffffff;
border-radius: 16px;
overflow: hidden;
font-family: var(--font-sans);
border: 1px solid var(--gray6);
box-shadow: var(--cmdk-shadow);
outline: none;
.dark & {
background: var(--gray2);
}
}
[cmdk-framer-header] {
display: flex;
align-items: center;
gap: 8px;
height: 48px;
padding: 0 8px;
border-bottom: 1px solid var(--gray5);
margin-bottom: 12px;
padding-bottom: 8px;
svg {
width: 20px;
height: 20px;
color: var(--gray9);
transform: translateY(1px);
}
}
[cmdk-input] {
font-family: var(--font-sans);
border: none;
width: 100%;
font-size: 16px;
outline: none;
background: var(--bg);
color: var(--gray12);
&::placeholder {
color: var(--gray9);
}
}
[cmdk-item] {
content-visibility: auto;
cursor: pointer;
border-radius: 12px;
font-size: 14px;
display: flex;
align-items: center;
gap: 12px;
color: var(--gray12);
padding: 8px 8px;
margin-right: 8px;
font-weight: 500;
transition: all 150ms ease;
transition-property: none;
&[data-selected='true'] {
background: var(--blue9);
color: #ffffff;
[cmdk-framer-item-subtitle] {
color: #ffffff;
}
}
&[data-disabled='true'] {
color: var(--gray8);
cursor: not-allowed;
}
& + [cmdk-item] {
margin-top: 4px;
}
svg {
width: 16px;
height: 16px;
color: #ffffff;
}
}
[cmdk-framer-icon-wrapper] {
display: flex;
align-items: center;
justify-content: center;
min-width: 32px;
height: 32px;
background: orange;
border-radius: 8px;
}
[cmdk-framer-item-meta] {
display: flex;
flex-direction: column;
gap: 4px;
}
[cmdk-framer-item-subtitle] {
font-size: 12px;
font-weight: 400;
color: var(--gray11);
}
[cmdk-framer-items] {
min-height: 308px;
display: flex;
}
[cmdk-framer-left] {
width: 40%;
}
[cmdk-framer-separator] {
width: 1px;
border: 0;
margin-right: 8px;
background: var(--gray6);
}
[cmdk-framer-right] {
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
margin-left: 8px;
width: 60%;
button {
width: 120px;
height: 40px;
background: var(--blue9);
border-radius: 6px;
font-weight: 500;
color: white;
font-size: 14px;
}
input[type='text'] {
height: 40px;
width: 160px;
border: 1px solid var(--gray6);
background: #ffffff;
border-radius: 6px;
padding: 0 8px;
font-size: 14px;
font-family: var(--font-sans);
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.08);
&::placeholder {
color: var(--gray9);
}
@media (prefers-color-scheme: dark) {
background: var(--gray3);
}
}
[cmdk-framer-radio] {
display: flex;
align-items: center;
gap: 4px;
color: var(--gray12);
font-weight: 500;
font-size: 14px;
accent-color: var(--blue9);
input {
width: 20px;
height: 20px;
}
}
img {
width: 40px;
height: 40px;
border-radius: 9999px;
border: 1px solid var(--gray6);
}
[cmdk-framer-container] {
width: 100px;
height: 100px;
background: var(--blue9);
border-radius: 16px;
}
[cmdk-framer-badge] {
background: var(--blue3);
padding: 0 8px;
height: 28px;
font-size: 14px;
line-height: 28px;
color: var(--blue11);
border-radius: 9999px;
font-weight: 500;
}
[cmdk-framer-slider] {
height: 20px;
width: 200px;
background: linear-gradient(90deg, var(--blue9) 40%, var(--gray3) 0%);
border-radius: 9999px;
div {
width: 20px;
height: 20px;
background: #ffffff;
border-radius: 9999px;
box-shadow: 0 1px 3px -1px rgba(0, 0, 0, 0.32);
transform: translateX(70px);
}
}
}
[cmdk-list] {
overflow: auto;
}
[cmdk-separator] {
height: 1px;
width: 100%;
background: var(--gray5);
margin: 4px 0;
}
[cmdk-group-heading] {
user-select: none;
font-size: 12px;
color: var(--gray11);
padding: 0 8px;
display: flex;
align-items: center;
margin-bottom: 8px;
}
[cmdk-empty] {
font-size: 14px;
padding: 32px;
white-space: pre-wrap;
color: var(--gray11);
}
}
@media (max-width: 640px) {
.framer {
[cmdk-framer-icon-wrapper] {
}
[cmdk-framer-item-subtitle] {
display: none;
}
}
}
Notable implementation details
Controlled value drives the live preview panel. The component lifts
value into state and passes it to Command via the value / onValueChange props. The right-hand preview pane switches on this same state value to render the matching component — {value === 'Button' && <Button />} and so on. Keyboard navigation (arrow keys) updates value automatically, so the preview tracks focus without any extra event handlers.Two-column layout inside
Command.List. Instead of relying on the default block flow, the [cmdk-framer-items] wrapper uses display: flex to place a 40% left column (the item list) and a 60% right column (the preview) side by side, separated by a 1 px <hr>. This layout is entirely in CSS — Command.List is not aware of the split and continues to manage filtering and keyboard navigation normally.Subtitle hidden on small screens. The
[cmdk-framer-item-subtitle] element is set to display: none at widths below 640 px via a media query, keeping the item height compact on mobile without changing any JSX. The icon wrapper and primary label remain visible.You can replace the static preview components with anything — a real component from your design system, a code snippet, or a rich-text description. Because the preview is driven by a plain React state string, swapping in async-loaded content is straightforward: fetch on
onValueChange and render a loading skeleton in the right panel while the request is in flight.