Repository navigation
Releases
yugen-ui 0.16.0
Minor Changes
- Charts: moving the pointer over LineChart, AreaChart and BarChart no longer recomputes the chart (#352). Scales, paths, the screen reader label of every point and the layers that do not change on hover are kept until the data, the props or the width change, and the points share one set of event handlers, so a hover step only redraws the crosshair, the tooltip and, for bars, the bars whose dimming changes. A hover step goes from 9.7 to 1.1 ms at 500 points and from 39 to 1.1 ms at 2,000 (three series, jsdom), and a keyboard step from 43 to 9.6 ms at 2,000. Colors shared by a series (line markers, bars) and the gridlines are set once on the series group instead of on every mark: a 4 × 200 LineChart with markers has 16 inline styles instead of 1,014 (−30% markup), a 60 × 4 BarChart 13 instead of 490 (−14%). The drawn pixels, keyboard navigation and screen reader output are unchanged; points now carry a
data-iattribute.{ BarChart, LineChart }grows from 30.2 to 31.1 kB gzip. NewuseElementSize({ enabled }): withfalsethe hook measures nothing and adds no ResizeObserver. Sparkline passesenabled: falsewhenwidthis a number, so 200 fixed-width Sparklines mount in one render instead of three, with no observers. - New
yugenHtmlAttributes()andyugenThemeScript()for server-rendered and prerendered apps, so the first paint uses the right theme (#348).<html {...yugenHtmlAttributes({ theme, brand, dir })}>writes the same attributes as<YugenProvider applyToDocument>into the first HTML.yugenThemeScript({ storageKey })returns a small inline script for<head>that setsdata-themebefore the first paint, from the saved choice (a theme name, or JSON withtheme,brandanddir) or else fromprefers-contrastandprefers-color-scheme. Both are plain functions that work in a Next.js Server Component.YugenProvider applyToDocumentnow writes the attributes in a layout effect, before the browser paints, instead of after it. - New
useYugenTheme()({ theme, brand, dir }) anduseYugenLocale()(the Intl locale): unlikeuseYugen(), a component that reads one of them does not re-render when the other changes.YugenProviderkeeps the theme in its own context, so a theme switch no longer re-renders every control that readsdefaultsormessages: with 1,800 controls and stable children (a Next.jsProviderscomponent, a wrapper that passeschildren), it goes from about 66 ms and 1,500 re-renders to 1.4 ms and none.messageswritten inline (messages={{ dialog: { close: "Close" } }},{ ...messagesVi, … }) is now compared by value likedefaults, so a parent re-render with the same strings no longer re-renders those controls (66 → 0.1 ms). Charts, CodeBlock, the date and time pickers and the other components that need only the theme or the locale use the new hooks.useYugen()returns the same fields as before (#347). - New subpath imports (#344): every component folder is also a path of the package, as in
import { Button } from "yugen-ui/Button",yugen-ui/Chartoryugen-ui/DatePicker, plusyugen-ui/hooks,yugen-ui/AppShell/Sidebar,yugen-ui/messages-enandyugen-ui/messages-vi. A subpath loads only that component and what it uses, which matters where nothing tree-shakes the package: tests, server rendering in Node and dev servers. A coldimport { Button }in Node loads 14 modules in about 60 ms fromyugen-ui/Button, against 498 modules in about 1.6 s fromyugen-ui. Production bundles keep the same size, and the root and the subpaths load the same files, so both can be used in one app.yugen-ui/_internal/*stays private. The Quick start page lists the paths and shows Next.jsoptimizePackageImportsfor apps that keep importing from the root.
Patch Changes
- Calendar no longer bundles the Vietnamese date-fns locale: it checks the locale code instead of importing
vi. English apps save about 2 kB gzip on every date component:{ Calendar }goes from 32.4 to 30.4 kB and{ DatePicker }from 58.8 to 56.8 kB (Rolldown, as in Vite 8). Vietnamese apps still get the locale throughcalendarMessagesVi/messagesVi, and the short weekday names (CN, T2…) work as before (#349). - Leaner CSS floor (#353). The library's 19 keyframes now live inside
@theme, so Tailwind only outputs the ones ananimate-*utility (or ananimationdeclaration) in your app uses: withtheme-core.css, a Button-only app goes from 20 keyframes to 1 (9.17 → 8.86 kB gzip in a Vite build) and the floor with no components from 7.15 to 6.85 kB. Utility and keyframe names are unchanged, includinganimate-shimmerandanimate-indeterminate; WavyUnderline uses the newanimate-wave-flow. As with Tailwind's own keyframes, they are written at the end of the output: an app that defines its own@keyframeswith one of these names (fade-in,sweep…) should declare it inside@themefor it to win.tokens.cssno longer carries the@themeblock and chart keyframes ofcharts.css, so it is plain CSS with custom properties only (8.22 → 8.02 kB gzip).styles.csskeeps the keyframes its components use and drops the unusedshimmerandindeterminate.theme.cssis now@import "./theme-core.css"plus its@sourceline instead of a second copy of the theme (64 kB less in the package). - Components with class variants (Button, Input, Badge, Card, Tag, Avatar, Label, Link, Select, Textarea, MessageBar, ButtonGroup, Image, SwatchPicker and the ToggleButton checked layer) merge their classes once per combination of variant props instead of on every render (#355). Server-rendering 1,000 Buttons takes half the time (about a third less with a
className), re-rendering them in the browser 44–51% less (30–32% with aclassName), and the docs' server-rendered pages 2–11% less. The exportedbuttonVariants,buttonGroupVariants,linkVariantsandimageVariantstake the same arguments and return the merged string: the classes the component renders, which is whatcn(buttonVariants(…))returned before.cnkeeps 2,000 merged strings instead of 500, so a large page no longer evicts its own entries. Copied source (yugen add, the shadcn registry) gainslib/cvx.tsnext tolib/cn.ts. - Deprecate
YugenProvider'swithToasterprop with a development warning and point templates and documentation to an explicit<Toaster />child. The prop remains available until 1.0.0. - Parts that only one option needs now load on demand (#350).
Navno longer imports Tooltip: the AppShellSidebarpasses the icon-rail tooltip to it, so a Nav outside AppShell goes from 29.9 to 12.0 kB gzip (Rolldown, as in Vite 8). Breadcrumb loads the menu of its "…" button only whenmaxDisplayedItemscollapses items (initial chunk 40.2 → 13.5 kB), and StreamingMarkdown loads the citation card only when the text has citations (49.3 → 27.3 kB). Until the part arrives, which starts right after the first client render, the button or chip renders with the same size, classes and ARIA; a click or key press in that window opens the menu or card once it arrives, and focus moves to the real button. Server rendering and hydration always render that placeholder, so both sides produce the same HTML. A lean dashboard (YugenProvider, Nav, Breadcrumb, Card, Button, Badge, Field, Input) goes from 51.2 to 32.2 kB and an AI chat page (YugenProvider, StreamingMarkdown, PromptInput, MessageScroller, Reasoning) from 63.8 to 54.1 kB; apps that already use Menu, Tooltip or Popover elsewhere see little change. Tests that open the Breadcrumb menu or a citation card right after rendering need to wait for it (findByRole). With esbuild code splitting (splitting: true), an import from the package root puts these parts into the first chunk even when the app does not use them, because esbuild assigns whole files to chunks; import from subpaths such asyugen-ui/Breadcrumbthere. - Combobox and TagPicker no longer use cmdk: a small built-in listbox engine handles the highlighted option,
aria-activedescendantand the keyboard (#351).{ Combobox }goes from 42.83 to 38.92 kB gzip and{ TagPicker }from 50.56 to 41.01 kB; Command keeps cmdk. With 1,000 options an arrow key now takes one render that updates only the two options whose highlight changed (Chromium: about 40 → 2.6 ms per key, typing 30 → 7 ms per key, opening 300 → 210 ms). Keyboard and the look are unchanged; options keeprole="option",data-selectedanddata-disabled, but no longer carrycmdk-*attributes, so tests that query[cmdk-item]inside a Combobox or TagPicker should queryrole="option"instead. The listbox is now named by the field label (aria-labelledby, which Field sets) instead of the fixed English "Suggestions"; without one it reuses the input'saria-label, and with neither it uses the newlistLabelmessage (messages.combobox.listLabel,messages.tagPicker.listLabel: "Suggestions" / "Gợi ý"). TagPicker loads Sortable only withreorderable: the server and the first render show plain tags of the same size, and dragging and Alt + arrow keys work as soon as it has loaded (tests should wait for it, for example for[data-sortable-item]). A tag that has focus when Sortable arrives keeps it. - Fix types under TypeScript
module: "node16"/"nodenext"(#343): the root declarations pointed at the Chart, AIKit and hooks modules without a.jsending, so 72 exports (BarChart, LineChart, StreamingMarkdown, PromptInput, useDisclosure, useHotkeys…) failed with "has no exported member".MenubarMenuno longer names@radix-ui/react-contextin its type, a package yugen-ui does not depend on. CI now type-checks every export from anodenextproject and runs Are the Types Wrong on the package. - Fix three details of the published package (#382). Deprecation warnings are in English and link to https://trandat1114.github.io/Yugen-UI/concepts/versioning instead of the old
#/URL. TheAppShellcookie gets `sec...
@yugen-ui/cli 0.8.0
@yugen-ui/cli 0.8.0 and create-yugen-ui 0.8.0.
yugen css --watchkeeps the lean CSS file current while source imports change. The bundled Next.js template runs it beside
next dev; Vite templates include@yugen-ui/cli/viteandyugenCss().initwires the Vite plugin into an existing
Tailwind CSS v4 project.--watchcannot be combined with--check.init,doctorandthemenow print an explicit<Toaster />inside the root<YugenProvider>instead of the deprecated
withToasterprop.yugen css: writesyugen-ui.csswith@import "yugen-ui/theme-core.css";and one
@import "yugen-ui/sources/<Folder>.css";per component folder your code imports, instead oftheme.csswith every
component. On the templates the gzipped CSS goes from about 26 kB to 12–20 kB (−24% to −54%). Imports are read with
a small lexer, so examples inside strings, comments or JSX text don't count;import * as,export *and
import()ofyugen-uifall back totheme.css.--checkexits with 1 when the file is out of date;--src
limits the folders it reads;--precompilecompiles plain CSS for apps without Tailwind (26.8 kB → 12.8–21.1 kB)
with the project's owntailwindcss,@tailwindcss/nodeand@tailwindcss/oxide(#169).init(package mode, Tailwind CSS v4) writesyugen-ui.cssand imports it instead ofyugen-ui/theme.css. A CSS
file that already importstheme.cssis left as it is.addin package mode adds the component toyugen-ui.csswhen the app has one.doctoracceptsyugen-ui/theme-core.css(it reported "theme not imported"), warns whenyugen-ui.cssis out of
date or not imported, and names the components imported without theirsources/<Folder>.css.- No runtime dependencies: own prompts on
node:readlineand colors withnode:utilstyleTextreplace
@clack/promptsandpicocolors(#381). - Bundled templates ship
package.jsonas_package.json;createrenames it back. Scanners no longer read the
templates' manifests as dependencies of the CLI (#381). create --refno longer readsGITHUB_TOKEN/GH_TOKEN(#381).add/updaterefuse registry file paths that leave the target folder and dependency specs that are not npm
package specs; on Windows the package manager that launched the CLI runs without a shell (#381).LICENSEfile in@yugen-ui/cliandcreate-yugen-ui;homepagepoints to the path URL of the CLI page.
Full notes: packages/cli/CHANGELOG.md · News
yugen-ui 0.15.0
Minor Changes
-
New prop names from the pre-1.0 API review (#157), so the same idea has the same name everywhere: Carousel
gap="extra-small" | "small" | "medium" | "large" | "extra-large"(default"small"), TreeonSelectionChange, DatePicker and DateRangePickeronValueChange(receivesnullwhen cleared, likevalue), Listappearance, RatingDisplayshowValue(defaulttrue), toast optiondismissible(defaulttrue), CarouselNavContainerpreviousLabeland AutocompletenoResultsText. Sheet and NotificationCenterbreakpointtake the same tokens as AppShell ("lg"…"5xl", default"3xl"= 48rem = 768px). Also new: TimePickeronValueChange(Date | null)next toonTimeChange, CarouselactiveIndex/defaultActiveIndex, and StepperdefaultActiveStep.The old names keep working until 1.0 and print a one-time warning in development: Carousel
gap="XS" | "S" | "M" | "L" | "XL"andcircular, TreeonSelectedChange, DatePickeronSelectDate, DateRangePickeronSelectRange, Listvariant, RatingDisplayhideValue, toasthideDismiss, CarouselNavContainerprevLabel, AutocompleteemptyMessage, a px number for Sheet / NotificationCenterbreakpoint, andformatDateVi. The unsuffixed…Messagesconstants (for examplecarouselMessages) are marked@deprecatedin favour of…MessagesVi/…MessagesEn. -
More names from the pre-1.0 API review (#157), the rows planned for 0.16, shipped early: CarouselNavContainer
showAutoplayToggle(Carousel's ownautoplayis the autoplay state), TimelineItemintent="error"(like MessageBar, Toast and Field), Stat and StatTilesize="extra-large", Dividerorientation="horizontal" | "vertical"and TeachingPopoverFooterorientation.Deprecated (they keep working until 1.0 and print a one-time warning in development): CarouselNavContainer
autoplay, TimelineItemintent="danger", Statsize="hero", Dividervertical, TeachingPopoverFooterlayout, and three exports that leave the package in 1.0:highlightRanges(internal helper ofHighlightMatch),getOverflowGroups(useuseIsOverflowGroupVisible(groupId)) and the top-leveldispatchToast(usetoast()oruseToast().dispatchToast, which do not warn). -
Breaking:
yugen-uino longer depends on@fluentui/react-icons(about 180 MB installed, plus the Griffel CSS-in-JS runtime). The 159 icons used inside components now ship with the library as small inline SVG components generated from Fluent System Icons, with the same paths, sizes and accessibility attributes, so components look the same. Apps that import icons from@fluentui/react-iconsthemselves and relied on it being installed withyugen-uimust add it to their own dependencies (npm i @fluentui/react-icons); the templates already do. Icon slots size any SVG with CSS, so other icon sets such aslucide-reactwork in them too (#320). -
New
ColorPicker: a saturation / brightness area, hue and optional opacity (alpha) sliders, HEX / RGB / HSL inputs, a screen color picker where the browser supports the EyeDropper API, and preset colors through SwatchPicker (swatches). The value is hex;onValueChangealso gets rgb / hsl / hsv.parseColoris exported, and built-in strings live inmessages.colorPicker(#173). -
New
FormattedInputwithformat="phone" | "card" | "currency": formats as you type and keeps the caret in place, including edits in the middle and Backspace over a separator.value/onValueChangeuse the raw value (digits, or a decimal like"1234.5"); withname, forms submit the raw value. Phone masks follow thelocaleregion (ormask), card numbers group by card type, and currency uses Intl with the providerlocaleandcurrency. Also exported:applyMask,getPhoneMask,getCardMask(#173). -
Yugen Labs:
glassNavigationDefaults, a set of default props forYugenProviderthat gives every navigation component with glassmaterial="glass"in one place (#230):<YugenProvider defaults={glassNavigationDefaults}>, or{ ...glassNavigationDefaults, Button: { … } }together with other defaults. It covers Toolbar, TabsList, Nav, MenuPopover, MenuSubPopover, PopoverSurface, TooltipContent, DialogSurface, DrawerSurface and SheetContent; amaterialprop on an instance still wins. MenuSubPopover exports its props type,MenuSubPopoverProps. -
New
MonthPicker,YearPickerandDateTimePickerin the DatePicker family: the same field, popover,value/defaultValue/onValueChange(Date | null),minDate/maxDate,clearable,formatDateand locale handling as DatePicker. MonthPicker and YearPicker show a 12-cell grid with arrow keys, Home / End and PageUp / PageDown; DateTimePicker pairs the Calendar with a TimePicker (timeIncrement,hourCycle). Built-in strings live inmessages.monthPicker,messages.yearPickerandmessages.dateTimePicker(#173). -
New
NavigationMenufor website headers (#168), built on Radix Navigation Menu (new dependency@radix-ui/react-navigation-menu):NavigationMenuList,NavigationMenuItem,NavigationMenuTrigger,NavigationMenuContent,NavigationMenuLink(activesetsaria-current="page";iconanddescriptioninside a panel;asChildfor router links) andNavigationMenuIndicator. Hover intent with a short delay,activationMode="manual"to open on click only, keyboard support per the WAI-ARIA disclosure navigation pattern, one floating viewport that resizes to the open panel, RTL. The<nav>label comes frommessages.navigationMenu. -
New
PasswordInput: an Input with a show / hide button (aria-pressed, keeps focus in the field), a Caps Lock note read through a live region, and an optional strength meter (strength, or your own scoring function;getPasswordStrengthis exported). Built-in strings live inmessages.passwordInput(#173). -
Prose reads its fonts and rhythm from CSS variables:
--prose-font-body,--prose-font-heading,--prose-font-mono,--prose-size,--prose-leadingand--prose-flow(space between blocks). With none of them set it looks exactly as before. New presets in the theme:yugen-prose-docs,yugen-prose-article,yugen-prose-chatandyugen-prose-compact. The docs have a Typeset page that builds your own preset and copies the CSS (#244). -
YugenProvidertakesdefaultsanddensity(#171).defaults={{ Button: { shape: "circular" }, Input: { appearance: "filled-darker" } }}sets props for every instance of a component in that part of the UI, typed per component; a prop on the instance still wins and nested providers merge per component.density="compact"gives controls (buttons, fields, pickers, tabs, toolbars, tables, Tree, Nav…) size small by default and scales spacing by 0.9375;"comfortable"scales spacing by 1.125. Spacing comes from adata-densityattribute intheme.css(--spacingand the spacing tokens, the same factors as the Theme Designer), so prerendered HTML is right before hydration.useYugen()also returnsdensity. Each component reads its defaults with one context read. -
Breaking: React 19 or later is required (
peerDependenciesreact/react-dom>=19). React 18.3 was supported through 0.14; it gets no fixes upstream since 2024-04, and CI no longer tests it. Apps on React 18 can stay onyugen-ui@0.14until they upgrade (#62). -
Components are plain function components that take
refas a prop (React 19) instead offorwardRefwrappers. Passing arefworks as before, andReact.ComponentRef<typeof Button>andReact.ComponentProps<typeof Button>still give the element type and the props (withref). In the type declarations each component is now a function such asButton(props: ButtonProps & { ref?: React.Ref<HTMLButtonElement> })rather than aReact.ForwardRefExoticComponent, so code that spelled outForwardRefExoticComponentfor a Yugen component should usetypeof ButtonorReact.ComponentType<…>.DataGridandDataGridColumnPickerare declared as generic functions directly. Components that keep their own ref next to yours (Carousel, Sheet, Toolbar, FileUpload and others) now call the cleanup function that a callback ref returns when the element is removed (#62). -
YugenProvider scrollLockchooses whether the page scrollbar stays while Menu, ContextMenu or Dropdown is open (#243). These surfaces lock page scrolling through Radix (react-remove-scroll), which hides the scrollbar and adds a body margin in its place."hide-scrollbar"keeps that behavior and stays the default in 0.x; with"keep-scrollbar"the scrollbar stays and nothing shifts, while wheel and touch scrolling outside the surface are still blocked. WithapplyToDocumentthe provider writesdata-yugen-scroll-lockto<html>; apps without the provider can set the attribute themselves (the CSS is intheme.css). Menu and ContextMenu documentmodal={false}for a menu that doesn't lock scrolling at all. 1.0 will switch the default to"keep-scrollbar". -
New
StatusPageandErrorBoundary(#238).StatusPageis a page for HTTP errors and app states:status(400, 401, 403, 404, 408, 410, 429, 500, 502, 503, 504,"offline","update") picks the built-in title, description and code frommessages.statusPage;primaryAction/secondaryActiontake your router's buttons or links,errorIdshows a copyable error ID,autoFocusmoves focus to the heading.ErrorBoundarycatches render errors and shows a 500 page with Try again, or "A new version is available" with Reload when a lazily loaded file fails after a deploy;fallback,onErrorandresetKeyscustomise it. Also exported:isChunkLoadError,statusPageCopy.
Patch Changes
- Untrusted content can no longer stall or crash the page (#165). Markdown and StreamingMarkdown cap nesting (32 block levels, 16 inline levels) and stop scanning unclosed brackets and emphasis markers early: deeply nested quotes or emphasis used to ...
@yugen-ui/cli 0.7.0
@yugen-ui/cli 0.7.0 and create-yugen-ui 0.7.0.
doctorreports React 18 as an error: yugen-ui 0.15 needs React 19 or later.- Template
docsreads its pages withReact.use. - Vite templates use TypeScript 7 (
^7.0.2, the native compiler):npm run buildtype-checks several times
faster.next-starterstays on TypeScript 6, becausenext buildtype-checks through TypeScript's JavaScript API. - Vite templates catch render errors with
ErrorBoundaryfrom yugen-ui 0.15: a page that fails shows a status page with
Try again (or Reload when a file failed to load after a deploy) instead of a blank screen.saasandstartershow
a 404 page for unknown paths instead of the home page, andlandingwrites a static404.htmlat build time.
Full notes: packages/cli/CHANGELOG.md · News
yugen-ui 0.14.0
Minor Changes
-
New
AppShell(#161): the frame of an app, withAppShellHeader,AppShellMain,AppShellAside,AppShellFooterand aSidebar(SidebarHeader,SidebarContent,SidebarFooter,SidebarGroup,SidebarTrigger,SidebarRail). Frombreakpointup (a container query on the shell, namedapp-shell) the sidebar sits in the layout and collapses to an icon rail (collapsible="icon", Nav labels move to Tooltips) or hides ("offcanvas"); below it the same content opens in a Drawer that closes when a link is followed or a Nav item is chosen.layout="header"puts the top bar across the full width with the sidebar below it;scroll="page"lets the whole page scroll with a sticky top bar and sidebar, for content sites (the top bar height is--app-shell-header).Sidebar resizableturnsSidebarRailinto a keyboard-operable splitter. Ctrl+B / ⌘B toggles the sidebar (shortcut), except in text fields, contenteditable and during IME composition; with several AppShells on a page only the one that has focus or was clicked last responds, andSidebarTriggershows the label and the shortcut in its Tooltip.persistKeykeeps the collapsed state and width in a cookie (read it on the server withreadAppShellCookie); the Drawer is never saved. When the frame crosses the breakpoint with the Drawer open, it closes and focus returns to the trigger, or to the main region if the trigger is hidden. Skip link to the main region,useAppShell()for custom parts, strings inmessages.appShell.NavItemgainstooltip. The SaaS, Dashboard, AI chat, Admin, Docs, Store, Blog, Landing and Starter templates use it. Thanks @dave-otf! -
New
yugen-ui/theme-core.cssandyugen-ui/sources/<Component>.css(#169).theme.cssmakes Tailwind scan every component, so every app ships the CSS of all of them.theme-core.cssis the same theme without that scan: add one@import "yugen-ui/sources/<Folder>.css"per component the app uses; each file also covers the components it uses inside (SplitButton.cssincludes Menu and Button).yugen-ui/sources/index.jsonmaps every export to its file. On the templates this takes CSS from about 25 kB to 14–19 kB gzip.theme.cssstays the zero-config default. -
New
Markdown(#263): renders static Markdown (articles, release notes, CMS fields) withProsetypography, through the same safe parser asStreamingMarkdown(no HTML,javascript:anddata:links keep only their label). Code fences useCodeBlock, tables scroll inside a labelled region, task lists read "Done" / "Not done".inlinerenders inline Markdown only, in a<span>, for list items and table cells. Relative links (/path,#id) are kept and external links open in a new tab;renderLinkhands every link to the app's router.headingOffset(default 1, so#ish2),headingIds(ids from the heading text,slugifyHeading),breaks,size. Strings inmessages.markdown.parseMarkdowngains arelativeLinksoption (off by default, soStreamingMarkdownstill keeps absolute links only),parseInlineMarkdownparses one line, andsanitizeHreftakes{ relative: true }. -
Breaking: built-in strings are English by default. Components show and announce English text ("Close", "Loading…", chart descriptions, live announcements) unless you pass
messages, andlocaledefaults to"en-US"(dates, times, numbers, and a 12-hour TimePicker). For Vietnamese, as before:<YugenProvider messages={messagesVi} locale="vi-VN">. NewmessagesViand per-component…MessagesVifor copied source;…Messageswithout a suffix stays the Vietnamese set so existing imports keep working, andmessagesEn/…MessagesEnare the defaults. Helpers follow the same defaults:formatFileSize,validateFiles, the NotificationCenter time formatters, TimePicker'sgetDefaultHourCycle/formatTime/parseTimeString, and the DatePicker range presets. -
New shared hooks, the ones the components use themselves (#172):
useControllableState,useDisclosure,useLocalStorage(synced across hooks with the same key and across tabs;serialize/deserializefor keys that are not JSON),useClipboard,useHotkeys(modis ⌘ on Apple and Ctrl elsewhere; skips form fields, IME composition and held keys;start/endarrows follow RTL),useDebouncedValue,useIntersectionanduseElementSize(measures before the first paint).useMediaQuerymoves next to them; importing it fromyugen-uior from Sheet still works. Docs page "Hooks". Thanks @giabao12-hali!Components now use them instead of their own copies, with no visible change: controlled / uncontrolled state goes through
useControllableStatein every component except Sheet's snap point and Trace's auto-expand (a callback is no longer called when the value does not change, for exampleuseTour().start()while the tour is already open), charts measure withuseElementSize, the copy buttons useuseClipboardand now report a refused copy instead of showing "Copied", andPackageManagerTabskeeps its saved choice throughuseLocalStorage. -
New
Sortable(#175):Sortable,SortableItem,SortableHandleandSortableGroupreorder lists with a mouse, pen, finger or the keyboard (Space or Enter on the handle picks the item up, arrow keys move it, Space or Enter drops it, Escape cancels), and announce every step throughuseAnnounce. Without dragging, click a handle to pick its item up and another item's handle to put it there. Vertical, horizontal (RTL-aware) and grid lists;SortableGroupmoves items between lists (Kanban columns); the nearest scroll container scrolls near its edges; items slide into place unless reduced motion is on.onValueChangeruns during the drag,onSortEndonce on drop.SortableItem handlemakes the whole item the drag source andshortcutsmoves it with Alt + arrow keys, for items that already use Space / Enter.arrayMovehelper, strings inmessages.sortable. Written in-house: about 6.5 kB gzip, no drag-and-drop dependency.DataGridgainscolumnOrder(andgetOrderedColumns);DataGridColumnPickerreorders columns whenonColumnOrderChangeis set (drag an item or Alt + ↑ ↓).TagPickergainsreorderable.
Patch Changes
CodeTabsandPackageManagerTabs:classNamenow sizes the outer box. Aw-fullblock inside a flex row (a centered demo, a card) used to keep the width of its tab bar and code and run past a narrow screen; it now fits and the tabs wrap.
Full notes: CHANGELOG.md · News
@yugen-ui/cli 0.6.0
@yugen-ui/cli 0.6.0 and create-yugen-ui 0.6.0.
- Breaking: requires Node.js 24 or newer. Yugen UI supports the two newest Node.js LTS lines (24 and 26 today).
- Templates
starter,saas,blog,dashboard,ai-chat,admin,docs,storeandlandingare built on
AppShellfrom yugen-ui 0.14.0: collapsible sidebar (icon rail, Drawer on narrow screens), Ctrl+B / ⌘B, skip link. - Template
admin: Board page (Kanban) withSortable, saved on drop, rolled back with a toast when the request fails.
Full notes: packages/cli/CHANGELOG.md · News
yugen-ui 0.13.0
Minor Changes
-
Glass, part 2 (Yugen Labs).
MenuPopoverandPopoverSurfacewithmaterialgrow out of the button that opens them and shrink back into it when they close (scale and position from the trigger, read when the animation starts); with reduced motion they keep the plain fade. Newmaterial="glass"onSliderandSwitch: while pressed or dragged the thumb turns to glass, larger on Slider so the track shows through it, longer on Switch. Names may change before 1.0. -
New
GlassRefraction(Yugen Labs): render it once at the app root and the edges of everyglass,glass-clearandglass-tintedsurface bend what is behind them, like the rim of a lens, while the middle stays frosted so text keeps its contrast. Each size and corner radius gets one SVG filter (a displacement map from Snell's law over a convex rim), applied throughbackdrop-filter; only Chromium browsers draw it, Safari and Firefox keep the regular glass. It turns off wherever the blur does (Reduce transparency, Increase contrast, forced colors, the high-contrast theme, glass inside glass) through the new--glassLensFiltertoken. Names may change before 1.0. -
New
Sonner: notifications that stack in a corner, newest in front, and fan out into a list on hover or keyboard focus. Callsonner("…"),sonner.success / info / warning / error / loadingfrom anywhere;sonner.promiseturns a loading notification into success or error in place, and calling again with the sameidupdates it. Action and cancel buttons,richColors,closeButton, swipe to dismiss, F8 to reach the region. Built on Radix Toast, no new dependency. Strings inmessages.sonner.New display components (#174):
Timeline/TimelineItem(detailed and compact),DescriptionList/DescriptionItem(columns that drop on narrow containers, inline layout, copy button; strings inmessages.descriptionList),Stat(the stable version ofStatTile, with achartslot; strings inmessages.stat) andProse(typography for Markdown and CMS HTML through the newyugen-prosetheme utility, zero-specificity selectors, opt out withnot-prose).StatTileis nowStatplus a Sparkline and readsmessages.stat;messages.chart.increase / decrease / noChangeare deprecated.CodeBlock,Table,QuoteandTimelinecarrynot-prose.
Patch Changes
Checkbox,SwitchandField: inside a<form>, the hidden input (or the hidden<select>ofDropdown) that Radix adds for form submission stays inside the control. It used to escape a scrolling container and add blank space at the bottom of the page.- Notice: React 18.3 stays supported for the rest of 0.x; from 1.0, Yugen UI supports React 19 only. Apps still on React 18 should move to React 19 before updating to 1.0.
Full notes: CHANGELOG.md · News
@yugen-ui/cli 0.5.1
@yugen-ui/cli 0.5.1 and create-yugen-ui 0.5.0.
- Template
glass: cherry blossom trips in Kyoto, Tokyo, Hirosaki and around Mount Fuji (photos from Wikimedia Commons,
credited with their license),<GlassRefraction />at the app root, a Settings preview of the bars over a bright,
a blossom and a night photo, and a world map on Explore with every trip pinned at its coordinates. - Templates
bloganddocs: Markdown articles are styled withProsefrom yugen-ui instead of classes on every tag.
Full notes: packages/cli/CHANGELOG.md · News
yugen-ui 0.12.0
Minor Changes
-
DataGrid: people can choose which columns are shown. The new
hiddenColumnsprop hides columns;DataGridColumnPickeris the "Columns" button that edits it, and it also works with Table. The menu stays open while columns are checked, ahideable: falsecolumn and the last visible column can't be hidden, and the sorted column keeps sorting the rows (with an arrow in the menu) while hidden. Hidden columns keep their resized width, pinned columns are re-measured, and keyboard focus stays on the same column instead of the same index. Columns can now setlabelinstead ofrenderHeaderCell.useDataGridColumnVisibilityandgetVisibleColumnsexpose the logic.Menu: long menus scroll inside the viewport instead of overflowing it, and
MenuItemCheckbox/MenuItemRadioacceptsecondaryContentlikeMenuItem. -
Glass (Yugen Labs): a translucent material for the navigation layer that floats above content, inspired by Liquid Glass. Turn it on per component with
material="glass" | "glass-clear"on Toolbar, TabsList, Nav, MenuPopover, PopoverSurface, TooltipContent, DialogSurface, DrawerSurface and SheetContent,appearance="glass" | "glass-prominent"on Button andappearance="glass"on Input / SearchBox. TabsList getsminimizedand theuseScrollMinimizehook for tab bars that shrink while scrolling down. New utilities:glass,glass-clear,glass-tinted,glass-scrim,scroll-edge,scroll-edge-above,rounded-concentric. Text keeps 4.5:1 over any backdrop; glass turns opaque with reduced transparency, increased contrast, the high-contrast theme, forced colors or withoutbackdrop-filter. Names may change before 1.0.
Patch Changes
- ContextMenu, Menubar and every submenu scroll inside the viewport when they are long, like Menu. On touch screens, where there is no hover, Table row actions, subtle selection checkboxes (Table and DataGrid) and Tree item actions are always visible. DataGrid and Table use tabular figures, so numbers line up in a column.
Full notes: CHANGELOG.md · News
@yugen-ui/cli 0.5.0
@yugen-ui/cli 0.5.0 and create-yugen-ui 0.5.0.
- New template:
glass(create --template glass), a travel journal with glass navigation over photos. - New template:
landing(create --template landing), a product landing page with pricing, FAQ and a sign-up
form; the first screen and the SEO tags are written intoindex.htmlat build time. - New template:
admin(create --template admin), customers and orders with a server-paged DataGrid, drawer forms
with validation, optimistic updates, and sign-in with a one-time code. - New template:
next-starter(create --template next-starter), a Next.js App Router project with the theme in a
cookie so the server renders it.create --langworks without anindex.html. - New template:
docs(create --template docs), a documentation site built from Markdown files, with Ctrl K search
and an HTML file for every page. - New template:
store(create --template store), a small shop with filters kept in the URL, a cart in a Sheet and a
validated multi-step checkout; prices in US dollars, or dong with--lang vi. - Templates pin
yugen-ui@^0.12.0. The SaaS template uses real paths (/analytics) instead of#/analytics, and the
single-page templates ship deploy configs:public/_redirects(Netlify),vercel.jsonandnpm run build:gh-pages
(GitHub Pages).
Full notes: packages/cli/CHANGELOG.md · News