Announcing lynx-ui
← All Postslynx-ui has been quietly open-sourced since we gave an early preview at React Advanced London last December. After months of polishing components, building the documentation site, and adding examples, today we are excited to announce it as generally available.
Native Foundations, Web Velocity
Built-in elements and XElement give Lynx the low-level capabilities that matter: fast scrolling, precise gestures, and native rendering. But products are not built from atoms alone. That is where components belong. At Lynx, native provides the foundation; the web-inspired frontend stack provides the extension layer for composition, state, styling, and product-specific behavior.
lynx-ui delivers on this layering principle: preserve native user experience, deliver the velocity of the web.
lynx-ui's ScrollView is built
on top of the native <scroll-view>
primitive
Composable Primitives
Encapsulation can become a trap. lynx-ui does not treat components as black boxes with endlessly growing prop surfaces. Instead, it is an unstyled component library where each component is a primitive that handles behavior and state, but ships with no visual design. A primitive is composed of parts that you render and style independently.
Popover shows the idea. It is not a single opaque component, but a composition of parts with separate responsibilities: PopoverRoot owns state, PopoverTrigger defines intent, PopoverPositioner handles placement, and PopoverContent stays structurally independent.
Because primitives are unstyled, the same composable model creates a foundation for design systems. You can define your own themes through the styling and theming system, or follow the shadcn/ui pattern to compose themed wrappers on top of the primitives.
LUNA
LUNA is a reference design language we built on top of that foundation.
It grows from Lynx's signature gradient, adapting the brand expression into a softer palette for UI: warm pinks and rose tones moving into lavender and aqua. In LUNA, gradients act as first-class visual materials for expressing form and movement, giving components a sense of changing mediums. That sensitivity also carries into token names: LUNA describes how surfaces are felt, not where they are placed. ambient dissolves into the background, faint sits near the threshold of perception, veil and film create soft translucent layers.
Programmable Interaction
Components built around continuous input need two things at once: highly customizable behavior and low-latency response. A swipe, drag, or snap is judged frame by frame. If the visual response trails behind the gesture, the component may still work, but it no longer feels native.
Lynx's dual-thread model defaults JavaScript to the background thread, keeping the main thread free for rendering. But Main-Thread Script can move interaction logic onto the main thread when it matters, making per-frame behavior fully programmable without crossing a thread boundary. Swiper shows the idea directly: drag input feeds transform updates frame by frame, so the card follows the gesture instead of catching up to it later.
A 'main thread' function passed to
main-thread:customAnimation runs per-frame logic on the main
thread
With native foundations and programmable interaction in place, motion becomes practical, not just decorative.
Motion
Motion is one of the most popular animation libraries in the Web community, supporting both spring-based and bezier-based transitions. Thanks to the programmability that Main-Thread Script brings, we adapted Motion for Lynx as @lynx-js/motion, a thin layer that reuses Motion's source directly, and ship an experimental version together with lynx-ui. If you know Motion on the web, you already know how to use it in Lynx.
Sheet shows why that matters. Drag, resistance, release, and settling need to read as one continuous behavior. With Main-Thread Script keeping interaction close to rendering and Motion defining how the surface moves, the sheet feels held, not just played back.
Sheet uses @lynx-js/motion under the hood for
spring-driven drag and settle transitions
Try it today
lynx-ui is available on iOS, Android, and HarmonyOS today, with partial Web and Desktop support on the horizon. Read the introduction to get oriented, or jump straight to the quick start to install @lynx-js/lynx-ui-*.
To see the components in action, grab Lynx Explorer, scan the QR codes in the component demos, and see them running right away. Or bring it into your own Lynx app and try it in a real product flow.
We want lynx-ui to grow from the way real apps are built. If it feels great, gets in your way, or leaves something missing, let us know in the lynx-family/lynx-ui repository. Help shape what comes next.