Guides

Why use Vy UI

What a component library is actually worth on Lynx, how the headless and styled layers differ, and when copying the source with the CLI beats depending on the package.

Most component libraries are sold on the size of their catalogue, which is the least useful number to compare on Lynx. A button is an afternoon, a card is twenty minutes, and if the catalogue were the whole value proposition you would be right to skip the dependency and write the six components your app actually needs.

The value sits in the layer underneath, where Lynx behaves unlike the browser you tested in. Lynx drops what its engine cannot handle rather than erroring on it, so a broken component looks correct in the web preview, logs nothing, and renders wrong on a phone. Every one of those costs a build, a device, and an afternoon of narrowing down which of your forty declarations the engine discarded.

We maintain Vy UI, so read this as an argument rather than a survey. The Lynx UI frameworks guide compares the options with less of a stake in the answer.

The components are the easy part

Here is a sample of what a component library on Lynx has to encode, all of which is documented in Theming on Lynx because we found each one the slow way.

Lynx resolves a single level of var(), so a semantic token pointing at a palette token evaluates to nothing and your carefully layered theme collapses to white backgrounds and black borders on device. The @lynx-js/tailwind-preset allowlists 57 of Tailwind's 179 core plugins, so ring-2 is a no-op and a focus ring has to be a spread-only box-shadow. Tailwind v3 has no half-step spacing above 3.5, so size-4.5 compiles to nothing at all and your slider thumb quietly loses its dimensions. Icons are rasterized rather than rendered live, so text-primary-500 on a wrapper does nothing and the hex has to be resolved at render time. data-[state=open]: variants never match, so state styling runs through parallel ui-* classes while data-state stays for assistive technology. Empty slots and v-if branches realize as zero-size nodes, which gap-* then counts as real children and pushes your icon off-centre.

None of that is exotic. It is the normal cost of a runtime that is younger than the assumptions in your CSS, and it is paid once per library rather than once per application.

Behaviour is where the time actually goes

Styling failures are visible, so you fix them. Behaviour failures are the ones that ship.

A drag has to run on the main thread, because a gesture that round-trips through the background thread drops frames under exactly the conditions users notice. Vy UI puts Swiper, SwipeAction, Sortable, Draggable, FeedList, and ScrollView on one shared main-thread gesture core, which also means the worklet registration problem is solved once. That problem is worth naming, because it is the single most common way a Lynx app breaks in production: bundlers skip node_modules when collecting main-thread code, the worklets never register, and the first drag throws TypeError: cannot read property 'bind' of undefined. Installation covers the one config line that fixes it, and npx @vyui/cli check fails your CI if it goes missing.

Overlays are the other reservoir of hidden work. A dialog needs focus handling and dismissal, a bottom sheet needs velocity-aware drag physics, and a select needs keyboard and screen-reader wiring that Lynx does not infer from the element tree. Animation end events can be lost on web when a child unmounts mid-transition, which leaves an invisible backdrop mounted over your app swallowing every tap, so our presence layer carries a wall-clock watchdog that exists purely because of that failure.

If you write React, use lynx-ui

@lynx-js/lynx-ui is the Lynx team's own headless library for ReactLynx, built by the people who build the runtime, shipped as one package per component. If your team writes React, that is the right starting point and Vy UI cannot help you, since Vue Lynx is a separate custom renderer and the two do not interoperate.

What lynx-ui does not give you is a styled layer. It is headless by design, so the visual tier is yours to build, and no ReactLynx equivalent to shadcn/ui or Vant sits on top of it yet. Vy UI covers both tiers, which is the substantive difference between the ecosystems rather than a difference in component count.

Three ways to consume it

The layers exist so you can take as much opinion as you want and no more.

@vyui/core is 47 headless primitives. They own state, focus, keyboard handling, and gestures, and they render unstyled <view> and <text> with nothing to override. Reach for this when you have a design system already, or when the kit's aesthetic is not yours and you would rather not fight a theme. You still get the runtime knowledge above, which is the part that took the time.

@vyui/kit is 48 styled components on those primitives, themed through Tailwind Variants. A three-tier token system flips the entire set into dark mode through a single class rather than per-component dark: variants, and every component takes a ui prop for slot-level overrides. Reach for this when you want to be building your product this week.

The CLI copies kit component source into your repository instead of resolving it from node_modules, in the shadcn/ui model. Running npx @vyui/cli add select fetches the component from a registry, pulls in the primitives it depends on, installs the npm packages it needs, rewrites the imports to match your own path aliases, and leaves plain source files in your project.

The benefit of that model is that a component you need to change becomes a file you edit rather than a theme API you negotiate with. Restyling stops depending on whether we anticipated the override, forking one component does not fork the library, and reading the implementation is a jump-to-definition instead of a trip to GitHub. You give up automatic updates on the files you copied, which is the trade, and it is a good one for the two or three components every app ends up rewriting anyway. The two paths mix freely, so importing most of the kit from the package and owning the three components you have opinions about is the common shape.

What you are accepting

Vy UI is alpha and Vue Lynx is earlier than alpha, so component names, props, and slots will move under you. That is the real cost, and it is larger than the dependency risk people usually weigh.

Accessibility on web is incomplete in a way it is not on native, because Lynx emits accessibility-* properties that VoiceOver and TalkBack consume directly while browsers ignore them entirely. Internationalization is early, since Intl is not fully present in the Lynx runtime. Both are documented gaps rather than things you will discover after committing.

If your application is small enough that you need a button, a card, and one list, write them. The argument here starts at the point where you need a sheet that drags, a select that a screen reader can use, and a theme that survives contact with a device.

Lynx UI frameworks

Every component library available for Lynx today, and which framework each binds to.

Theming on Lynx

The engine constraints behind every theme decision, and what breaks silently.

CLI

Copy component source into your own repo, shadcn-style.

Get started

Install the packages and render a first component.