reka-ui Documentation

An open-source UI component library for building high-quality, accessible design systems and web apps for Vue. Previously Radix Vue

RAW Doc

Technical Documentation: unovue/reka-ui

โ„น๏ธ Provenance: Hybrid Fusion: unovue/reka-ui (README + 4 In-Tree Chapters) ยท CodeWiki Reference ยท Recency: Active (< 180 days)

1. Project Overview & Quickstart (unovue/reka-ui)

design by: icarusgkx, melkam

Installation

bash
pnpm add radix-vue
bash
npm install radix-vue
bash
yarn add radix-vue

Documentation

For full documentation, visit radix-vue.com.

Releases

For changelog, visit releases.

Contributing

We would love to have your contributions! All PRs all welcomed! We need help building the core components, docs, tests, stories! Join our discord and we will get you up and running!

Dev Setup

Docs

  1. Clone the repo
  2. Run pnpm i
  3. Run pnpm build to run build radix-vue locally
  4. Run pnpm docs:dev to run vitepress
  5. Open http://localhost:5173

Package

  1. Clone the repo
  2. Run pnpm i
  3. Run pnpm story:dev to run histoire (storybook)
  4. Open http://localhost:6006

Authors

Credits

All credits go to these open-source works and resources

2. In-Tree Documentation Chapters (unovue/reka-ui)

File: README.md

design by: icarusgkx, melkam

Installation

bash
pnpm add radix-vue
bash
npm install radix-vue
bash
yarn add radix-vue

Documentation

For full documentation, visit radix-vue.com.

Releases

For changelog, visit releases.

Contributing

We would love to have your contributions! All PRs all welcomed! We need help building the core components, docs, tests, stories! Join our discord and we will get you up and running!

Dev Setup

Docs

  1. Clone the repo
  2. Run pnpm i
  3. Run pnpm build to run build radix-vue locally
  4. Run pnpm docs:dev to run vitepress
  5. Open http://localhost:5173

Package

  1. Clone the repo
  2. Run pnpm i
  3. Run pnpm story:dev to run histoire (storybook)
  4. Open http://localhost:6006

Authors

Credits

All credits go to these open-source works and resources


File: docs/content/guides/animation.md


title: Animation/Transition

Animation

Animate Radix Primitives with CSS keyframes, native Vue Transition or JavaScript animation library of your choice.

Adding animation to Radix Primitives should feel similar to any other component, but there are some caveats noted here in regards to exiting animations with JS animation libraries.

Animating with CSS animation

The simplest way to animate Primitives is with CSS.

You can use CSS animation to animate both mount and unmount phases. The latter is possible because the Radix Primitives will suspend unmount while your animation plays out.

css
@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes fadeOut {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

.DialogOverlay[data-state="open"],
.DialogContent[data-state="open"] {
  animation: fadeIn 300ms ease-out;
}

.DialogOverlay[data-state="closed"],
.DialogContent[data-state="closed"] {
  animation: fadeOut 300ms ease-in;
}

Animating with Vue Transition

Other than using CSS animation, you might prefer to use the native Vue ``. Great news! It should be as easy as wrapping component (that has forceMount prop), and you are done!

vue line=11,13,14,19,25-33
<script setup lang="ts">
import { DialogClose, DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger, } from 'radix-vue'
</script>

<template>
  <DialogRoot v-model:open="open">
    <DialogTrigger>
      Edit profile
    </DialogTrigger>
    <DialogPortal>
      
        <DialogOverlay />
      
      
        <DialogContent>
          <h1>Hello from inside the Dialog!</h1>
          <DialogClose>Close</DialogClose>
        </DialogContent>
      
    </DialogPortal>
  </DialogRoot>
</template>

<style>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>

::: tip
Futhemore, we discovered that Motion One, a Web Animations API based animation library works perfectly with Radix Vue.

Check out this Stackblitz Demo ๐Ÿคฉ
:::

Delegating unmounting for JavaScript Animation

When many stateful Primitives are hidden from view, they are actually removed from the DOM. JavaScript animation libraries need control of the unmounting phase, so we provide the forceMount prop on many components to allow consumers to delegate the mounting and unmounting of children based on the animation state determined by those libraries.

For example, if you want to use @vueuse/motion to animate a Dialog, you would do so by conditionally rendering the dialog Overlay and Content parts based on the animation state from one of its composable like useSpring:

vue line=32,34,41
<script setup lang="ts">
import { DialogClose, DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle, DialogTrigger, } from 'radix-vue'
import { reactive, ref, watch } from 'vue'
import { useSpring } from '@vueuse/motion'

const stages = {
  initial: { opacity: 0, scale: 0, top: 0, },
  enter: { opacity: 1, scale: 1, top: 50, },
  leave: { opacity: 0, scale: 0.6, top: 30, },
}

const styles = reactive(stages.initial)
const { set } = useSpring(styles, {
  damping: 8,
  stiffness: 200,
})

const open = ref(false)
watch(open, () => {
  if (open.value)
    set(stages.enter)
  else
    set(stages.leave)
})
</script>

<template>
  <DialogRoot v-model:open="open">
    <DialogTrigger>
      Edit profile
    </DialogTrigger>
    <DialogPortal v-if="styles.opacity !== 0">
      <DialogOverlay
        force-mount
        :style="{
          opacity: styles.opacity,
          transform: `scale(${styles.scale})`,
        }"
      />
      <DialogContent
        force-mount
        :style="{
          opacity: styles.opacity,
          top: `${styles.top}%`,
        }"
      >
        <h1>Hello from inside the Dialog!</h1>
        <DialogClose>Close</DialogClose>
      </DialogContent>
    </DialogPortal>
  </DialogRoot>
</template>

::: tip
Check out this Stackblitz Demo
:::


File: docs/content/guides/composition.md


title: Composition

Composition

Use the `asChild` prop to compose Radix's functionality onto alternative element types or your own Vue components.

All Radix primitive parts that render a DOM element accept an asChild prop. When asChild is set to true, Radix Vue will not render a default DOM element, instead passing the props and behavior required to make it functional to the first child of the slots.

Changing the element type

In the majority of cases you shouldnโ€™t need to modify the element type as Radix has been designed to provide the most appropriate defaults. However, there are cases where it is helpful to do so.

A good example is with TooltipTrigger. By default this part is rendered as a button, though you may want to add a tooltip to a link (a tag) as well. Let's see how you can achieve this using asChild:

vue{7}
<script setup lang="ts">
import { TooltipRoot, TooltipTrigger, TooltipPortal } from "radix-vue";
</script>

<template>
  <TooltipRoot>
    <TooltipTrigger asChild>
      [Radix Vue](https://www.radix-vue.com/)
    </TooltipTrigger>
    <TooltipPortal>โ€ฆ</TooltipPortal>
  </TooltipRoot>
</template>

If you do decide to change the underlying element type, it is your responsibility to ensure it remains accessible and functional. In the case of TooltipTrigger for example, it must be a focusable element that can respond to pointer and keyboard events. If you were to switch it to a div, it would no longer be accessible.

In reality, you will rarely modify the underlying DOM element like we've seen above. Instead it's more common to use your own Vue components. This is especially true for most Trigger parts, as you usually want to compose the functionality with the custom buttons and links in your design system.

Composing with your own Vue components

This works exactly the same as above, you pass asChild to the part and then wrap your own component with it.
However, there are a few gotchas to be aware of.

Composing multiple primitives

asChild can be used as deeply as you need to. This means it is a great way to compose multiple primitive's behavior together.
Here is an example of how you can compose TooltipTrigger and DialogTrigger together with your own button:

vue{9,10}
<script setup lang="ts">
import { TooltipRoot, TooltipTrigger, TooltipPortal, DialogRoot, DialogTrigger, DialogPortal } from "radix-vue";
import MyButton from from "@/components/MyButton.vue"
</script>

<template>
  <DialogRoot>
    <TooltipRoot>
      <TooltipTrigger asChild>
        <DialogTrigger asChild>
          <MyButton>Open dialog</MyButton>
        </DialogTrigger>
      </TooltipTrigger>
      <TooltipPortal>โ€ฆ</TooltipPortal>
    </TooltipRoot>

    <DialogPortal>...</DialogPortal>
  </DialogRoot>
</template>

File: docs/content/guides/dates.md


title: Dates & Times

Dates & Times

How to work with dates and times in Radix Vue.

::: tip
The inner-workings of our date-related components are heavily inspired by the research and work done
by the React Aria team at Adobe, who have created
robust date components that excel in terms of accessibility, user experience, and flexibility.
:::

The component depends on the @internationalized/date package, which solves a lot of the problems that come with working with dates and times in JavaScript.

We highly recommend reading through the documentation for the package to get a solid feel for how it
works, and you'll need to install it in your project to use the date-related components.

Date Objects

We use the DateValue objects provided by @internationalized/date to
represent dates in the various components. These objects are immutable, and provide information about
the type of date they represent:

  • CalendarDate: A date with no time component, such as 2023-10-11.
  • CalendarDateTime: A date with a time component, but without a timezone, such as
    2023-10-11T12:30:00.
  • ZonedDateTime: A date with a time component and a timezone, such as
    2023-10-11T21:00:00:00-04:00[America/New_York].

The benefit of using these objects is that we can be very specific about the type of date we want,
and the behavior of the builder will adapt to that type.

Additionally, you don't have to worry about wrangling timezones, daylight savings time, or any other
date-related nuance.

Utility Functions

This package also provides a number of utility functions which solves a lot of the problems that come with working with dates and times in JavaScript.

Specially designed to work well with @internationalized/date.

How to use?

text
/* Detailed source-code truncated for AI context efficiency. */

--- METRICS ---