Note
This repository is a fork of OkuUI and serves as a staging area for migrating Vue components to Single File Components (SFC). All contributions and changes will be merged back into the original repository upon completion.
An open-source UI component library for building high-quality, accessible design systems and web apps.
Oku Primitives is a low-level UI component library with a focus on accessibility, customization and developer experience. You can use these components either as the base layer of your design system or adopt them incrementally.
Website: Oku Website
Docs: Nuxt playground
Storybook: Storybook
pnpm i @perigee/vue-primitives
Main differences from RadixVue
-
I use let variables or useRef where React uses useRef. Radix-vue creates unnecessary reactive ref variables in all places, which is completely unnecessary.
-
I use the composeEventHandlers hook. This hook allows canceling events through preventDefault. Unfortunately, in Vue, handlers received from the parent component end up at the end of the array and are called last (I might have misunderstood the code, there may be inaccuracies).
-
I use attribute inheritance instead of redefining them in each component, generating unnecessary code. Moreover, it seems that Volar now has typing for attrs. This approach may change if it turns out to be inconvenient to use.
-
I do not use their useForwardExpose. A hook that replaces the original expose object to pass props outside. Why, if access to them is already available.
-
I do not use asChild for implementing primitives. Instead, I wrap the component's content in a hook and use it. I thought it was a bit cumbersome to use so many empty wrapper components when they can be eliminated. For example, the FocusScope wrapper is 3 components: FocusScope -> Primitive -> Slot. If there are 3 such wrappers, it is already a tree of 9+ components. This is currently a test implementation.
-
Slot [WIP] Discussion
-
The idea of discarding components and leaving only hooks that return props is currently being explored. For example, as in Zag and Melt. If the Vapor mod is released during our lifetime, this method will allow us to get rid of
Primitive
andSlot
(VDom). -
Different implementation of Collection without Map, VDom. Radix vue
-
Presence is just a hook for me. The same approach was found in Solid's Kobalte. In radix-vue, it is the reason for the absence of content on the first render in components like Accordion.
-
Availability of component context export for access in user code. It seems that this was promised to be added in Radix v2. I am not following.
-
An easier way to get the current element without
computed
. Radix-vue
Enter the component you want most in the components, leave the emojis and follow.
Developers can work on unclaimed components.
Component | Status | Hook v1 | Props | Note |
---|---|---|---|---|
Accordion | ✓ | ✓ | ✓ | |
AlertDialog | ✓ | ✓ | ✓ | |
AspectRatio | ✓ | ✓ | ✓ | |
Avatar | ✓ | ✓ | ✓ | TODO: PR from Radix |
Checkbox | ✓ | ✓ | ✓ | TODO: input |
Collapsible | ✓ | ✓ | ✓ | |
Context Menu | ✓ | ✓ | ✓ | |
Dialog | ✓ | ✓ | ✓ | |
DropdownMenu | ✓ | ✓ | ✓ | |
Form | ✖️ | ✖️ | ✖️ | |
HoverCard | ✓ | ✓ | ✓ | TODO: poligon; Fix: close |
Label | ✓ | ✓ | ✓ | |
Menubar | ✓ | ✓ | ✓ | |
NavigationMenu | 🚧 | 🚧 | ||
Popover | ✓ | ✓ | ✓ | |
Progress | ✓ | ✓ | ✓ | |
RadioGroup | ✓ | ✓ | ✓ | TODO: input |
ScrollArea | ✓ | ✓ | ✓ | |
Select | 🚧 | 🚧 | ||
Separator | ✓ | ✓ | ✓ | |
Slider | ✓ | ✓ | ✓ | |
Switch | ✓ | ✓ | ✓ | TODO: input |
Tabs | ✓ | ✓ | ✓ | |
Toast | ✓ | ✓ | ✓ | |
ToggleGroup | ✓ | ✓ | ✓ | |
Toggle | ✓ | ✓ | ✓ | |
Toolbar | ✓ | ✓ | ✓ | TODO: focus on MouseDown |
Tooltip | ✓ | ✓ | ✓ |
Utilites | Status | Hook v1 | Props | Note |
---|---|---|---|---|
Collection | ✓/🚧 | ✓ | ✖️ | TODO: array Items |
DismissableLayer | ✓/🚧 | ✓ | ✓ | TODO: Dismissable like Solid.js |
FocusScope | ✓ | ✓ | ✓ | |
Menu | ✓ | ✓ | ✓ | |
Popper | ✓ | ✓ | ✓ | TODO: Arrow |
Portal | ✓ | ✖️ | ✖️ | TODO: Dismissable like Solid.js |
Presence | ✓ | ✓ | ✖️ | |
Primitives | ✓ | ✖️ | ✖️ | |
RovingFocusGroup | ✓ | ✓ | ✓ | |
Slot | ✓ | ✖️ | ✖️ | TODO: remove VDom |
VisuallyHidden | ✓ | ✖️ | ✖️ |