Casey Baggz
Cerberus Admin
Celebrating the first release of 2026! This release adds new features and improvements to our entire ecosystem.
With a new year comes new goals. Our long-term vision has always been to create a "Design System Factory" that can be used to streamline design or development workflows.
This release marks a significant milestone in our journey towards this vision.
The Cerberus Preset has been updated to be more modular and customizable via the preset
option in the configuration. Today, we have officially broken out preset content into
their own packages to ensure each team is only using what they need.
We have broken presets into two groups (more to come in the future):
@cerberus/panda-preset & @cerberus/preset-cerberus-themeIf you haven't noticed, we have a new theme called Elysium. 👀
@cerberus/panda-preset: The core preset of non-theme related primitives.@cerberus/preset-cerberus-theme: The Cerberus theme.@cerberus/preset-acheron-theme: The Acheron theme.@cerberus/preset-elysium-theme: The Elysium theme.The Core preset will setup pretty much everything you need and additionally add the Cerberus Theme as the default theme. Theme packages will set the semantic tokens and add a condition selector for the theme.
If you only need the Cerberus Theme, you don't need to do anything.
Use JSR to install any preset package:
npx jsr add @cerberus/preset-elysium-themepnpm add jsr:@cerberus/preset-elysium-themebunx jsr add @cerberus/preset-elysium-themeIf you are using multiple themes in your app (like we do in the docs), we recommend the following steps:
panda.config.ts to include the new themes:import { createCerberusConfig, createCerberusPreset,} from '@cerberus/panda-preset'import { presetAcheronTheme, getThemeName as getAcheronThemeName,} from '@cerberus/preset-acheron-theme'import { presetElysiumTheme, getThemeName as getElysiumThemeName,} from '@cerberus/preset-elysium-theme'
export default createCerberusConfig({ // ...your existing config
presets: [createCerberusPreset(), presetAcheronTheme, presetElysiumTheme],
staticCss: { themes: ['cerberus', getAcheronThemeName(), getElysiumThemeName()], },})We have unleashed a massive amount of utility components and hooks to simplify common tasks and improve developer productivity.
The ClientOnly component renders its children only on the client side. This is
useful for components that need to access the DOM or browser APIs that are not
available on the server side.
import { ClientOnly } from '@cerberus/react'
export const WithFallback = () => ( <ClientOnly fallback={<div>Loading on the server...</div>}> <div>This content is only rendered on the client side.</div> </ClientOnly>)The DownloadTrigger component provides a convenient way to programmatically
trigger file downloads in web applications. It handles the complexities of
downloading files, whether they are URLs, Blobs, or other data types.
import { DownloadTrigger } from '@cerberus/react'
export const Basic = () => { return ( <DownloadTrigger data="Hello world" fileName="hello.txt" mimeType="text/plain"> Download txt </DownloadTrigger> )}Read the Download Trigger Docs
To support custom environments like an iframe, Shadow DOM or Electron, render
the EnvironmentProvider component to provide the environment context to all
Ark UI components.
import { EnvironmentProvider } from '@cerberus/react'import Frame from 'react-frame-component'
export const App = () => { return ( <Frame title="IFrame Context"> <EnvironmentProvider>{/* Your App */}</EnvironmentProvider> </Frame> )}The FocusTrap component helps maintain accessibility by ensuring keyboard focus
remains within a designated container until explicitly released.
import { cerberus, FocusTrap } from '@cerberus/react'import { useState } from 'react'
export const Basic = () => { const [trapped, setTrapped] = useState(false)
return ( <> <button onClick={() => setTrapped(true)}>Start Trap</button>
<FocusTrap returnFocusOnDeactivate={false} disabled={!trapped}> <cerberus.div> <input type="text" placeholder="input" /> <textarea placeholder="textarea" /> <button onClick={() => setTrapped(false)}>End Trap</button> </cerberus.div> </FocusTrap> </> )}The Format.Byte component extends the number formatting capabilities to
handle byte-specific formatting, including automatic unit conversion and display
options.
'use client'
import { Format } from '@cerberus/react'
export const ByteBasic = () => { return ( <div> File size: <Format.Byte value={1450.45} /> </div> )}The Format.Number component extends the number formatting capabilities to
handle number-specific formatting, including automatic unit conversion and display
options.
'use client'
import { Format } from '@cerberus/react'
export const NumberBasic = () => { return ( <div> File size: <Format.Number value={1450.45} /> </div> )}The relative time formatting logic is handled by the native Intl.RelativeTimeFormat API and smartly cached to avoid performance issues when using the same locale and options.
'use client'
import { Format } from '@cerberus/react'
export const RelativeTimeShort = () => { return ( <div> Edited <Format.RelativeTime value={new Date('2025-05-05')} style="short" /> </div> )}Read the Format Relative Time Docs
The Frame component is used to render a component in an iframe.
head prop to inject scripts and styles.'use client'
import { Frame } from '@cerberus/react'
export const Basic = () => { return ( <Frame title="Custom Frame" style={{ border: '1px solid #ccc', width: '100%', height: 'var(--height)' }} head={<style>{'body { background-color: #f0f0f0; }'}</style>} > <div style={{ padding: '40px' }}> <h1>Hello from inside the frame!</h1> <p>This content is rendered within our custom frame component using a Portal.</p> </div> </Frame> )}The Highlight component takes a text prop containing the full text and a query
prop specifying the text to highlight. It then renders the text with highlighted
portions wrapped in <mark> tags.
import { Highlight } from '@cerberus/react'
export const Basic = () => { return ( <Highlight query="ipsum" text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt" /> )}The JSON Tree View component takes a data prop containing the JSON data to be displayed.
It then renders the data in a tree-like structure with expandable nodes.
import { JsonTreeView } from '@cerberus/react'import { ChevronRightIcon } from '@carbon/icons-react'
export const Basic = () => { return ( <JsonTreeView.Root data={{ name: 'John Doe', age: 30, email: 'john.doe@example.com', tags: ['tag1', 'tag2', 'tag3'], address: { street: '123 Main St', city: 'Anytown', state: 'CA', zip: '12345', }, }} > <JsonTreeView.Tree arrow={<ChevronRightIcon />} /> </JsonTreeView.Root> )}Note, this is a stylized example. The actual implementation will be unstyled text.
The LocaleProvider component sets the locale for your app, formatting dates,
numbers, and other locale-specific data.
If no LocaleProvider is setup, the default locale for the app will be en-US
and therefore the direction will be ltr.
import { LocaleProvider } from '@cerberus/react'
export const App = () => { return <LocaleProvider locale="de-DE">{/* Your App */}</LocaleProvider>}Control the visibility of a child component using the Presence component.
By default the child component starts out as hidden and remains hidden after the
present state is toggled off. This is useful for situations where the element
needs to be hidden initially and continue to stay hidden after its presence is
no longer required.
'use client'
import { Presence } from '@cerberus/react'import { useState } from 'react'
export const Basic = () => { const [present, setPresent] = useState(false) return ( <> <button type="button" onClick={() => setPresent(!present)}> Toggle </button> <Presence present={present}>Hidden and Hidden</Presence> </> )}Additionally, we have also shipped the following:
Dialog and Accordion root providers and hookscombobox recipe uses correct _userInvalid conditionWe continue to enhance the Cerberus ecosystem with a focus on developer productivity and accessible design patterns. Coming up:
Thank you for being part of the Cerberus community! These updates are driven by your feedback and real-world usage patterns.
To upgrade to Cerberus v0.25.0, run:
npm run up:cerberuspnpm run up:cerberusbun run up:cerberus