Repository navigation
Added
@plexui/vue: Plex UI for Vue 3. Every component, icon and meaningful hook has a Vue counterpart with the same names, props, defaults and rendered markup, styled by the same@plexui/stylesCSS modules and checked against the React components by parity tests. Each component page has a Vue tab, and the Vue guide covers installation, the Vite plugin and SSR. The MCP server takesframework: "vue",llms-vue.txtdescribes the Vue API, andplexui.com/r/vueis a registry for the shadcn-vue CLI.InputGroup: an input or textarea with icons, text, buttons and menus attached inside one frame.InputGroup.Addonsits before or after the control (align="inline-start"/"inline-end") or as a header or footer row ("block-start"/"block-end");InputGroup.Buttonis a ghostButtonsized from the group;InputGroup.Textholds prefixes, units and counters. EveryInputsize from3xsto3xl, both variants,pill,disabledandinvalid. Also in@plexui/vueasInputGroup,InputGroupInput,InputGroupTextarea,InputGroupAddon,InputGroupButtonandInputGroupText.Menu.Itemtakes adescription: a second line under the label, with the label going semibold on its own. Same "item + subtitle" anatomy a Select option with a description already had, so a two-line menu item no longer needs hand-written typography.- Select accepts
checkPosition="none", which removes the indicator column from the list. A menu of one-shot actions, or a list whose option view states the selection itself, no longer reserves an empty 16px column in every row. Slideracceptsaria-labelandaria-labelledby, so a slider without a visiblelabelcan be named. Range thumbs keep theirMinimumandMaximumnames.MarkdownEditoracceptsaria-labelandaria-labelledbyfor its editable region, which a<label for>cannot name.Menu.ItemActionacceptsaria-label, so its icon-only button can be named.- DatePicker and DateRangePicker calendars move focus from the keyboard: the arrow keys by a day or a week, Home and End to the start or end of the week, Page Up and Page Down by a month. The calendar turns to the next or previous month when needed, and focus stays put rather than move to a day outside
minandmax. Kbd: a key or a keyboard shortcut such as ⌘K, in text, in a tooltip or at the end of a menu item.Kbd.Groupholds keys pressed together; three sizes,softandoutline, both mixing the surrounding text color so a key reads on any surface. Also in@plexui/vueasKbdandKbdGroup.Breadcrumb: the trail of pages above a page title. Anavlandmark around an ordered list;Breadcrumb.Itemis a link (hreforto, through thelinkComponentofPlexUIProvider), a button (onClick), a plain step or thecurrentpage (aria-current="page"). Customseparator,size="sm", and long trails wrap. Also in@plexui/vueasBreadcrumbandBreadcrumbItem(the separator is a slot).Tabstakeoverflow="menu": the tabs that do not fit move into a menu at the end of the row instead of a sideways scroll. When the active tab is a hidden one, the menu button shows its name and carries the selection; badges move into the menu with their tabs.overflowLabelsets the button's text.Dialog.Body(VueDialogBody): with it, only the body scrolls and the header and footer stay in view.Dialog.Contenttakesplacement(center,top,bottom,start,end,fullscreen) for search dialogs, bottom sheets and side panels,mobilePlacementfor 640px and below (a centered dialog that becomes a bottom sheet on phones), andonOpenAutoFocus/onCloseAutoFocus.Fieldtakes alabelAction: a link or small control at the end of the label row, such as "Forgot password?".CheckboxandRadioGroup.Itemtake adescription: a second line under the label, outside it, linked througharia-describedby.Switchalready had one.Menu.ItemandMenu.Linktakedangerfor destructive actions: the label and the highlight use the danger color.EmptyMessagetakessize="sm"for an empty panel, card section or list, andalign="start"for an empty state under a section heading.Alerttakesbanner: a full-width strip with square corners and lines above and below only, for offline, read-only or new-version notices.Inputtakesvariant="ghost": no border and no fill, for a field its container already frames, such as a search line at the top of a dialog.FieldErrortakesicon={false}for a message that stands alone, such as under a centered code input.CopyButtonandCopyTooltipreport the clipboard result throughonCopy(copied)(Vue: thecopyevent).--sidebar-menu-sub-max-heightsets the height an openSidebarMenuSubanimates to (1000px by default), so long lists are not cut off.SelecttakessearchSizefor the search field in its menu, such as2xlfor 44px touch targets on phones.@plexui/ui/styles/tailwind-utilities.cssis exported, for apps that import the token files one by one instead of@plexui/ui/css.
Changed
@plexui/mcp0.2.0: every tool takesframework: "vue"for the@plexui/vuedocs, andget_componentfinds components by their exported and part names.- The CSS now ships in its own package,
@plexui/styles: design tokens, globals and the CSS module of every component.@plexui/uidepends on it and re-exports it, so@import "@plexui/ui/css", the@plexui/ui/styles/*.cssfiles,@plexui/ui/viteand@plexui/ui/typeskeep working unchanged. Rendered markup and compiled CSS are identical to 0.19. Install@plexui/styleson its own to use the same styles from another framework. - Grouped Select menus separate their sections. A group heading is now smaller and semibold in the secondary color instead of an option-sized muted row, a rule runs between sections, and the heading starts at the row's content edge instead of being indented to the option labels.
SidebarGroupno longer acceptsonOpenChange. The group has no toggle of its own and never called it; setopenfrom your own control, and a closed group hides itsSidebarGroupContent.@plexui/uirequires React 19 inpeerDependencies. The components already used React 19 APIs (use(Context),<Context value>,refas a prop) and could not run on React 18.- Published modules use fully specified imports (
./Button.js,lodash/clamp.js), so the package resolves under webpack 5's strict ESM rules, Node ESM and TypeScriptNodeNext. ThePlexUIglobal types now ship with the declarations instead of being dropped from them. Fieldtakes its label size from the child control:<Field><Input size="sm" /></Field>gets ansmlabel without repeating the size. An explicitsizeon Field still wins, and a render prop keepsmd.FloatingLabelSelectshows its error as the same plain line asFloatingLabelInput, so the two read alike on one form. It used to renderFieldErrorwith an icon.- The
Alerticon sits on the first line of the message, next to the title, instead of in the middle of a title and a description. A one-line alert looks the same.
Fixed
checkPosition="none"also drops the indicator column from a group's expand row (optionsLimit.label). The row kept a 16px slot and sat indented under options that no longer had one.- Select menus are never narrower than the field they belong to.
listWidth="auto"still grows with the content, but the menu'smin-widthnow falls back to the trigger's width instead of collapsing to nothing. - Select menus line up with their trigger's edge.
align="start"/"end"no longer apply a hidden -5px offset that pushed the menu outside the field. - Select search inputs have a default accessible name and support
searchAriaLabelindependently of the trigger label. DatePicker's year search is namedSearch year. - DatePicker and DateRangePicker use a complete attribute selector when excluding exiting calendars from their height calculation.
- Grouped Select lists expose each group to assistive technology: a
role="group"named by its heading. The arrow keys still move through the options of every group in order, and the look is unchanged. - DatePicker month and year menus use Plex UI Select, with accessible names and consistent keyboard navigation and styling across browsers.
- Select and DatePicker now forward accessible labels, descriptions and invalid state to their interactive triggers.
aria-labelledbyincludes the visible selected value or placeholder, keeping both the field name and current selection available to assistive technology. - Select checkmarks are vertically centered on the title's first line at either position, including options with multiline descriptions.
CopyButtonwithout children, the copy action in everyCodeBlock, has an accessible name:Copy, thenCopiedafter a click.Sliderthumbs take their accessible name fromlabel(range thumbs keepMinimumandMaximum, as in "Price range Minimum"). In range mode the label no longer points at a missing input, and the reset button is labelled withresetTooltip.TagInputkeeps every tag when several are pasted at once (pastinga,b,cused to keep onlyc), stops atmaxTags, and no longer throws when a tag containing a double quote is selected.Selectoption lookup escapes values the same way.- DatePicker and DateRangePicker calendars keep the
minandmaxdays selectable. Amaxat midnight or aminlater in the day used to disable that whole day. - DatePicker and DateRangePicker month navigation buttons are labelled
Previous monthandNext month. The DateRangePicker month stepper also works with Enter and Space. SidebarProviderwithonOpenChangebut noopenexpands and collapses again. Controlled mode follows theopenprop;onOpenChangeis always called.Imagerenders a newsrcafter an earlier one failed to load.Switchno longer pointsaria-describedbyat a description it does not render (a description without a label).- A
CheckboxorSwitchwith a description inside aFieldwith one: the two descriptions have their own ids (the control's ends in-label-description) and the control is described by both. They shared an id, and a Switch dropped its own description. DataTablesupports uncontrolled row selection, filtering and column visibility, also with only anon*Changecallback (row.getIsSelected()threw without arowSelectionprop). It re-paginates whenpageSizechanges, including to and from0orInfinity, and labels its pagination buttons and rows-per-page select.- Space and Enter on the clear button of
SelectControlandFloatingLabelSelectclear the value instead of opening the list, also inside aMenu.Trigger. CopyTooltipcopies with Enter or Space, not only with a pointer press.TagInputwithmaxTags={0}(no limit, as the input already treated it) no longer renders a stray0where the counter goes.InputandTextareaforwardautoCompleteand setaria-invalidwheninvalidis true.FileUploadputsaria-invalidand its error description on the visible trigger instead of the hidden file input.TextLinkkeeps an explicittarget, asButtonLinkalready did.- A
TextLinkwithouthrefbut withonClickis focusable and runs its action on Enter and Space. ButtoncolorandDatePickertriggerDateFormatare optional in the types, matching their runtime defaults.Selectreturns focus to its trigger after choosing an option or pressing Escape; it used to drop focus to the page.- With
showTime,DatePickerkeeps the chosen date and time withinminandmax, and the time fields show the adjusted time. ProgressStepswithvariant="minimal"renders adivwithrole="progressbar"instead of anav, where that role is not allowed.- The header of the primary sorted
DataTablecolumn carriesaria-sort. StatCard's info tooltip can be reached with the keyboard and is announced as "More information".TagInputkeeps a tab stop whenmaxTagsis reached, so tags can still be removed from the keyboard.MarkdownEditortoolbar toggles expose their state througharia-pressed.FloatingLabelInputwithmultilineforwards props such asrequired,maxLengthand key handlers to its textarea, and resizes when a controlledvalueorrowschanges.Fieldnames controls that its label'sforcannot reach. The label has an id, and a child without its ownaria-label,aria-labelledbyorlabelgetsaria-labelledbypointing at it, so a Select or DatePicker trigger in a Field reads "Role, Admin" instead of only its value. A render prop receivesaria-labelledbyamong the field props.CopyButton(and so everyCodeBlockcopy button) andCopyTooltipshow the copied state only after the clipboard write succeeds; a failed write used to show the check mark anyway. A second click while the write is in flight no longer copies twice.- A long
FieldErrormessage wraps inside the field, and its icon stays on the first line. Sidebar: the collapsed header no longer hides or shrinks the collapse trigger; collapsed-state rules no longer hide labels, group labels and badges in an expanded sidebar nested inside a collapsed one; in React the phone layout is used on the first render instead of one frame of the desktop sidebar.- Toasts stay inside the screen on phones instead of keeping the 400px desktop width, with the same inset on both sides.
- The opaque soft fills (
--color-background-{info,success,warning,caution,danger,discovery}-softand their hover and active states) have dark-theme values: they stayed light, under text that turned light. Checkboxplays its check animation only for the checkbox in use, not for every checked box when a list first renders or a tab with checkboxes opens.OTPInputcells narrow to fit a 320px screen, and a field cleared from outside (a wrong code wiped by the form) puts the caret back in the first cell when the focus was in the field.Select's hidden form input uses its own class instead of Tailwind utilities, so it can no longer take the trigger's width in an app whose Tailwind build ordersw-fullaftersr-onlyor does not generatesr-only.- The
Tabsthumb follows the active tab when tabs are added, removed, reordered or relabelled. Menu.Triggerforwards its props andrefto the trigger element.AnimateLayoutGroupappliesinsertMethodandpreventInitialTransition.ButtonLink,TextLinkandMenu.Linktype their props from the link component set inPlexUIConfig, as the installation guide describes. The augmentation used to reach onlyPlexUIProvider, so<ButtonLink to="/x">with a routerLinkfailed to type-check.PlexUIOverridesstill works.SidebarMenuButtonwithasChildrenders the child element as the button. The button props used to land on an innerspanwrapped around the child, so a link lost the button styles andaria-current.Sidebarno longer imports the undeclared@radix-ui/react-slot, which strict installs (pnpm without hoisting, Yarn PnP) could not resolve.Fieldmerges itsaria-describedbywith the child's own and keeps the child's explicitaria-invalid.- An
AvatarwithonClickusesnameas its accessible name instead of announcing only the initial, or nothing for icon avatars. - A sidebar item's chevron turns only when that item is expanded, not when an item it is nested under is.
Slider, theuseBreakpointhook,useDocumentThemeand theuserAgenthelpers render on the server.useBreakpointreturnsfalseon the server and on the first client render, then reads the viewport;useDocumentThemereturnslightthere, then follows the document.Slidermarks follow new values and labels when their count stays the same (changingmin,maxandmarkstogether no longer throws), range marks are positioned, thumbs show a focus ring from the keyboard, the value input accepts negative numbers, and a typed value that has not been reported yet no longer overwrites a newer change.usePreviousreturns the value before the latest change.- Select's option list is a listbox:
aria-selectedfollows the selection,aria-activedescendantthe highlighted option, and multiple selection setsaria-multiselectable. Typeahead in grouped options picks the next match, Ctrl, Cmd and Alt shortcuts no longer change the value, a multiple Select withnamesubmits every value, and a disabled Select is neither submitted nor validated. FloatingLabelSelectused as a Select or Menu trigger opens from the keyboard and gets focus back when the list closes.- Clicking the frame, an adornment or the label of an
emailornumberInputorFloatingLabelInputno longer throws. Clear buttons keep focus in the field, andFloatingLabelInputkeeps an explicitaria-invalidsuch as the oneFieldpasses. OTPInputkeeps every digit in its cell,DateInputshows its value again when it loses focus with a partly typed date, a disabledTagInputcannot remove or add tags, andInputGroupkeeps its invalid border while focused.- DatePicker and DateRangePicker accept equal
minandmax, name every day with its full date, mark the selection witharia-pressedand today witharia-current, and theiridis optional. DateRangePicker disables shortcuts outsidemin,maxormaxRangeDays, and starts a fresh selection after its value is reset tonull. DataTableenableRowSelectionrenders the checkbox column it promised, rows withonRowClickwork from the keyboard, grouped headers span their columns, the rows-per-page select shows the real page size, and pagination stays while rows overflow it.MarkdownEditorplaces the caret where you click, saves links as links instead of escaped HTML, runs Cancel and Remove on Enter, and keeps focus inside its link dialog. TheCodeBlockcopy button shows its focus ring, and expanded code taller thanmaxExpandedHeightscrolls.FileUploadwithoutmultiplereplaces its file instead of adding a second one.- Clicking the dimmed area around a
Dialogcloses it. AMenu.Itemwith onlyonClickis interactive, a disabledMenu.Linkdoes not navigate, andMenu.Labelhas its 12px text again. ImageandAvatarshow an image that loaded before hydration.ButtonandBadgekeep aTooltiptrigger or a render-prop child intact.- A collapsed
SidebarMenuSubleaves the tab order, and anonClickonSidebarTriggerorSidebarMobileMenuButtonruns before the toggle and can cancel it. ButtonGroup.Texthas its padding and gap again,ButtongutterSize="3xs"has a style, transition groups render children keyed likeconstructor, andAnimateLayoutGroupapplieshideOverflowanditemAnchor.@plexui/uiand@plexui/vuedeclarations pass a consumer type check withskipLibCheckoff, also together (oneColumnMetaaugmentation).@types/luxonand@tanstack/table-coreare dependencies of the packages that use them.- The registry
buttonandmenuitems no longer re-export types that do not exist. The registrystylesitem is imported from your stylesheet after Tailwind and carries@source, so Tailwind generates the classes the components use. - The MCP server finds components by their exported and part names (
DataTable,Toaster,Dialog.Trigger), its React setup guide includes the layer order,@sourceandlinkComponent, andllms-full.txtis generated from the docs. @plexui/vue: Vue renders what React renders with radix-ui 1.8 (Tabsradiogroup, Tooltip content,aria-controlsonly while open, Popover and Dialog dismiss on the click after an outside press, RadioGroup, Checkbox and Switch form inputs) and follows every fix above. Vue-only fixes:Card,ButtonLinkandTextLinkgive vue-router'sRouterLinkato;DialogTrigger,DialogClose,MenuTriggerandFieldwork with a child forwarded through<slot />; closed Popover, Dialog and Select render no teleport on the server; Escape closes a Dialog with a forced-open Tooltip on the page;InputandFloatingLabelInputacceptreadonly; keyed multi-root<template v-for>items in transition groups;TagInputemits plain objects; DateRangePicker follows in-place edits of its range; missing props types are exported.
Full changelog: https://plexui.com/docs/changelog
Also published
@plexui/mcp@0.2.0