120k

Changelog

RSS

Latest updates and announcements.

July 2026 - React Aria

React Aria is now a first-class component base in shadcn/ui.

Build with React Aria Components alongside Base UI and Radix. Pick it in shadcn/create or initialize a project with --base aria. The CLI handles the dependencies, registry resolution, styles, and component installation.

What's New

  • A first-class React Aria base - Choose React Aria anywhere you can choose Base UI or Radix, including the CLI, presets, and shadcn/create.
  • Full component documentation - React Aria components have dedicated installation, usage, composition, examples, and API reference sections.
  • All eight styles - Use React Aria with Vega, Nova, Maia, Lyra, Mira, Luma, Rhea, or Sera.
  • Base-specific output - React Aria state selectors and dependencies are scoped to the Aria registry. Existing Base UI and Radix components are unchanged.

Start with React Aria

Use the aria base when initializing a project:

pnpm dlx shadcn@latest init --base aria

Or choose React Aria in shadcn/create. Once the project is initialized, shadcn add installs the React Aria implementation for each component.

Base UI remains the default, and Radix remains fully supported. Existing projects stay on their current base.

July 2026 - Introducing @shadcn/helpers

We are open sourcing @shadcn/helpers, a new package for small, focused helpers that make developing apps easier.

Starting with a helper for AI SDK and TanStack AI. It lets you write a conversation in code, then run it through the real useChat lifecycle without a model, API route, network request, or API key.

Your UI receives native framework messages and streaming events, so reasoning, tool calls, loading states, and message components behave the same way they do in production.

Here is a conversation written with the AI SDK helper:

import { createChat } from "@shadcn/helpers/ai-sdk"
 
const chat = createChat()
  .user("What changed in this release?")
  .assistant("The release adds keyboard shortcuts and faster search.")
  .user("Can you check the full release notes?")
  .sleep(500)
  .assistant(({ writer }) => {
    writer.stepStart()
 
    // Reasoning.
    writer.reasoning("I should read the release notes first.")
 
    // Tool call.
    writer
      .tool("getReleaseNotes", {
        title: "Reading release notes",
        input: { version: "latest" },
      })
      .sleep(500)
      .output({
        highlights: ["Keyboard shortcuts", "Faster search"],
      })
 
    // Source.
    writer.sourceUrl({
      title: "Release notes",
      url: "https://example.com/releases",
    })
 
    // Response.
    writer.text("The release adds keyboard shortcuts and faster search.")
  })

Pass its messages and transport to useChat:

import { useChat } from "@ai-sdk/react"
 
const initialMessages = chat.get(0)
const transport = chat.transport()
 
export function Chat() {
  const { messages } = useChat({
    messages: initialMessages,
    transport,
  })
}

The package includes two adapters:

Use it to build components, create previews and demos, write documentation, or test streaming interfaces with deterministic output and no backend dependency.

July 2026 - Introducing shadcn/typeset

Today we're releasing shadcn/typeset: a styling system for HTML and rendered markdown, in one CSS file.

Your app renders the same HTML elements everywhere: headings, paragraphs, lists, tables, and code. You style them for your blog, then your docs, and now chat. Typeset lets you style them once, then tune the rhythm for each context.

<div className="typeset">{content}</div>

Add one class and everything inside gets styled. Typeset follows the size of its container, uses your theme, and gives you three controls: size, leading, and flow.

You can create as many typesets as you need. Use a tighter rhythm for chat and a roomier one for docs:

.typeset-chat {
  --typeset-leading: 1.6;
  --typeset-flow: 1em;
}
 
.typeset-docs {
  --typeset-size: 15px;
  --typeset-leading: 1.75;
  --typeset-flow: 1.5em;
}
<div className="typeset typeset-chat">{message}</div>
<article className="typeset typeset-docs">{page}</article>

It's also designed for streaming, so new blocks don't restyle earlier ones. The file lives in your project. There's no package or config layer to work around.

Open the typeset builder to create yours, or read the Typeset docs for the full guide.

July 2026 - Base UI as the Default

Starting today, Base UI is the default component library in shadcn/ui.

First, a bit of history. When shadcn/ui launched in January 2023, it was built on Radix. At the time, nothing else came close. Unstyled headless components, great APIs, great accessibility, battle-tested in millions of apps.

Fast forward a few years and the same folks who built Radix are building something new: Base UI. They've done it once. Now they get to do it again, with everything they learned the first time.

Last year, Base UI tagged a beta and a lot of you asked if we are going to replace Radix with it. I said "the worst thing you can do for your production app is switch component libraries". I meant it, and it still holds. So instead of switching, we did the shadcn thing: we rebuilt every component for Base UI, kept the same abstraction, and let you choose. December brought npx shadcn create with both libraries. January brought full Base UI docs.

Then we watched what you did with it.


Why Now

  • Base UI is stable. It's at 1.6.0 with 6M+ weekly downloads.
  • It keeps getting better. The team ships new and useful components regularly.
  • We use it. Every new project we've started runs on Base UI.
  • You use it. Projects created on shadcn/create now pick Base UI over Radix 2 to 1.

The community already made the call. We're making it official.


What's Changed

  • New projects default to Base UI. Run npx shadcn init and Base UI is the default pick.
  • shadcn/create shows Base UI first.
  • The docs default to Base UI. Component pages open on the Base UI tab. Radix docs are one click away.

What This Means for You

Radix is not being deprecated. We still support it, and every update and new component will ship for both libraries (unless a component only exists in Base UI).

You do not need to migrate. Radix is a mature, tested library. We still run it in production today and we're not migrating. If your app works, keep shipping.

Prefer Radix for new projects? It's one flag away:

pnpm dlx shadcn init -b radix

If you have scripts or CI running shadcn init non-interactively and expecting Radix, add -b radix to keep them on the same path.

Building a registry? Ship a registry:base config if you want to pin a specific library. Items without one now init as Base UI.

Starting something new? We recommend Base UI.

When You're Ready to Migrate

You don't need to migrate. But if you want to, we built a skill for it:

pnpm dlx skills add shadcn/ui

Then ask your coding agent:

migrate accordion to base-ui

It's progressive by default: migrate one component and its usage at a time while your project stays green and shippable. Both libraries coexist while you work. Stop halfway, ship, come back next week and it picks up where you left off. Or ask for the whole project in one go.

Why a skill and not a codemod?

Because you own the code. You've added variants, changed classes, threaded new props. A codemod handles the components you never touched and breaks on the ones you did.

So we shipped knowledge instead: every rename, every prop change, every behavior difference, hand-checked against both libraries. Your agent reads it, figures out what you changed, and carries those changes over.

Mechanical things get fixed everywhere (asChild is now render). Behavior changes get flagged, never silently patched. You decide.

What a migration produces

Every run leaves three things:

  • Working code. Typechecked and built before it reports success.
  • A report per component in .migration/ at your project root: what changed, what was left alone, and a short checklist of things to verify by hand.
  • Clean git history. One commit per component, on a branch. Rollback is deleting the branch.

Here's what a report looks like:

.migration/accordion.md
# accordion
 
<!-- date, strategy used, and the one-line verdict -->
 
## Changed
 
<!-- every file touched, with what changed and why -->
 
## Left alone
 
<!-- files that look related but were intentionally not touched -->
 
## Behavior changes
 
<!-- differences that compile fine but act differently. flagged, not patched -->
 
## Verify by hand
 
<!-- a short checklist: open, click, tab through. takes a minute -->

No hidden state. Progress lives in your files and git history, so any agent, any session, any day picks up where the last one stopped.

It works with Claude Code, Cursor, or any agent that supports skills. We tested it on real projects: 60+ components, 36 of them on Radix. A full migration ran in about 25 minutes at roughly 10k tokens per component. Clean builds, customizations intact.

June 2026 - Components for Chat Interfaces

New Chat
How can I help you today?
Morning, shadcn!
What are we working on today? Press send to start a new conversation
I'm building a chat for our app and the scroll behavior is driving me nuts. Every time the AI streams a reply, the whole thread jumps around.
Demo is read only. Press send to send messages.
"use client"

import { useChat } from "@ai-sdk/react"

Today, we’re releasing a new set of components for building chat interfaces: MessageScroller, Message, Bubble, Attachment, and Marker.

This is the first phase of the chat components work. We’re taking it one piece at a time, reimagining the abstraction behind each part, and shipping them as shadcn/ui components you can copy, compose, and adapt to your product.

We are starting with the conversation layer: scrolling, message rows, bubbles, attachments, and markers.

We asked ourselves: what makes a great streaming chat experience? Then we abstracted the core rules into a set of primitives: MessageScroller.

pnpm dlx shadcn@latest add message-scroller message bubble attachment marker

MessageScroller

MessageScroller is the scroll container for a conversation. It handles the parts that are easy to get wrong: anchored turns, streamed replies, saved thread restore, prepended history, jump-to-message, scroll controls, and visibility tracking.

MessageScroller owns that behavior without owning your messages, AI state, transport, persistence, or model state. You bring the content renderer.

The MessageScroller is also available as an unstyled headless component in @shadcn/react.

Message, Bubble, Attachment, and Marker

The rest of the components cover the everyday pieces you need around the scroller.

  • Message lays out a row in the conversation with avatar, alignment, header, content, footer, and grouped messages.
  • Bubble renders the message surface, with variants, alignment, reactions, links, buttons, and collapsible content.
  • Attachment renders files and images with media, metadata, upload state, actions, and a full-card trigger that keeps actions separately clickable.
  • Marker renders status updates, system notes, bordered rows, and labeled separators for things like streaming state, tool activity, and date breaks.

They are intentionally small. Compose them together for AI chats, support inboxes, team threads, group chats, and product-specific conversations.

scroll-fade and shimmer

We also added two new CSS utilities for the details that make chat interfaces feel better.

scroll-fade adds scroll-aware edge fades to scroll containers. Use it on MessageScroller, ScrollArea, attachment rows, and any long list where you want to hint at more content without adding overlays or scroll listeners.

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
Item 11
Item 12
export function ScrollFadeDemo() {
  return (
    <div className="mx-auto w-full max-w-xs overflow-hidden rounded-2xl border">

shimmer adds a text shimmer for live status. Use it for things like "Thinking…", "Generating response…", running tools, and streaming markers.

Generating response…

export function ShimmerDemo() {
  return (
    <p className="shimmer text-sm text-muted-foreground">

Both utilities ship with shadcn/tailwind.css, so projects initialized with npx shadcn@latest init already have them.

@shadcn/react

We also created @shadcn/react, a new package for unstyled, headless React components.

The first primitive is @shadcn/react/message-scroller. The registry component wraps it with shadcn/ui styles, but the scroll behavior lives in the package: anchoring, auto-follow, prepend preservation, scroll commands, and visibility.

This lets us ship behavior without locking it to a visual style. You still get copy-and-paste components that match your project, and the hard interaction logic stays tested in one place.

Available now for Radix and Base UI.

AI Elements

This does not replace AI Elements. You can keep using AI Elements for AI interface components and patterns. This release is about bringing the core pieces of chat into shadcn/ui, one component at a time.

If you are already using a component from AI Elements, you do not need to rewrite your app. Keep what works. Try the shadcn/ui version when you want the newer abstraction, the updated styling, or support across Radix and Base UI.

The goal is to make these pieces easy to adopt independently. Replace one part, compose it with what you already have, and keep building.

View Components