The Rise of Lynx.js: A Newcomer JavaScript Framework Fueling TikTok’s Innovation

Frameworks like React Native and Flutter have long dominated cross-platform development, but Lynx JS introduces a fresh approach that seamlessly bridges web and mobile development, built on top of the React Engine.

Photo by Zdeněk Macháček on Unsplash

And lately, I’ve been busy balancing everything: work, life & hobby. Suddenly, just got news about new development tools from TikTok named Lynx.
Yes, you heard it! Named from a medium-sized wildcat known for its distinctive appearance and elusive nature.

From that moment made my curiosity to try! And here’s the review, the story of me trying Lynx.js

Introduction: Release Date

5th March 2025 marked the birth of Lynx.js, a family of technologies empowering developers to use their existing web skills to create truly native UIs for both mobile and web from a single codebase. Designed for diverse use cases and rich interactivity, Lynx delivers vibrant and engaging UIs for large-scale apps like TikTok, featuring a speedy, versatile rendering engine, performance-driven dual-threaded UI programming, modern Rust-based tooling, and more!

One week after the release date, I got an update post from daily.dev about the new JavaScript framework Lynx.js, right after that I’m starting to try it.

Initial Plan: Blog App

I was thinking to learn Lynx.js, not just randomly trying its component without planning what the app was going to make. Then the idea that comes to my mind is creating a blog app, a simple yet powerful implementation for a simple CRUD operation.

Looking for some inspiration on Dribble, I found this perfect UI Design Blog App by Syed Raju https://dribbble.com/shots/20805109-Blog-App

Mobile blog app design by Syed Raju on Dribble
Blog App by Syed Raju on Dribble

Configuration: Blog App

To start development, what we need is to install LynxExplorer.
Then run this command to create the project

npm create rspeedy@latest

Full documentation, quick start of Lynx.js right here

Fast-forward, after the configuration setup is finished, time to dive in.

screenshot lynxeplorer with ios simulator iphone 13
First Look LynxExplorer On iOS Simulator

Building: Blog App

Because Lynx.js uses React Engine, all the existing components are similar to React Native’s components.

Let’s take a look at how we place all elements in Lynx.js.

// hello world in lynx
export const App = () => {
return (
<view style="padding:5px;width:100%; height:100%;">
<text className="title">Hello Readers</text>
</view>
);
};
//hello world in react native
export const App = () => {
return (
<View style="padding:5px;width:100%; height:100%;">
<Text className="title">Hello Readers</Text>
</View>
);
};

One of the differences is a capitalized letter at the first. Lynx.js brings a vibe of how you code for the web starts with lowercase.

Review: Pros & Cons

What else can we see from Lynx.js?
Gradient background, all along in React Native, to produce a gradient, we need help from another library or/3rd party. With Lynx.js, we can easily do that as we do on the web. Define a custom class, then set the value.

/* global.css */
.bg-midnight-gradient {
background: linear-gradient(
to right,
rgb(29, 78, 216),
rgb(30, 64, 175),
rgb(17, 24, 39)
);
}

You may import it into your components, like this, set the class name we defined in the component.

const Header = () => {
return (
<view
class="bg-midnight-gradient container"
>
<text class="text-white">
Blogbust
</text>
</view>
);
};
export default Header;
screenshot how gradient background works on lynx.js
Gradient Background with Lynx

Another one is how to define route/navigation currently, when I write this review, the only way to handle multiple pages in Lynx is using react-router.

import { useNavigate, useLocation } from 'react-router';
import { IMAGE } from '../../constants/images.ts';
const BottomNavigation = () => {
const navigate = useNavigate();
const location = useLocation();
const handleNavigation = (path: string) => {
navigate(path);
};
const isActive = (path: string) => {
return location.pathname === path;
};
return (
<view>
<view>
{/* Home Menu */}
<view
bindtap={() => handleNavigation('/home')}>
<image
src={
isActive('/home') || isActive('/')
? IMAGE.ICON_HOME_ACTIVE
: IMAGE.ICON_HOME
}
style={{
width: '20px',
height: '20px',
}}
/>
<text>
Home
</text>
</view>
{/* Profile Menu */}
<view
bindtap={() => handleNavigation('/profile')}
>
<image
src={
isActive('/profile')
? IMAGE.ICON_PROFILE_ACTIVE
: IMAGE.ICON_PROFILE
}
style={{
width: '20px',
height: '20px',
}}
/>
<text>
Profile
</text>
</view>
</view>
</view>
);
};
export default BottomNavigation;

What if we need a library to use, for example, TailwindCSS?
To use a library is kinda tricky at the moment, still lacks its documentation, notes review from the community/developers themselves.

But yes, you can leverage 3rd party to use like any other JavaScript framework/library. Here’s how I managed to integrate TailwindCSS into Lynx’s project.

Install the necessary package first, like rsbuild-plugin-tailwind and the tailwindcss itself. Fyi, Lynx.js adapts rspack for the building tool called lynxjs/rspeedy based on Rust.

npm i tailwindcss @lynx-contrib/tailwind-preset rsbuild-plugin-tailwindcss

Create a tailwindcss configuration as usual, then import the latest rest libraries into lynx.config.ts

import { defineConfig } from '@lynx-js/rspeedy';
import { pluginTailwindCSS } from 'rsbuild-plugin-tailwindcss';
export default defineConfig({
plugins: [
...,
pluginTailwindCSS(),
],
});

Now, we can use className in our component similarly to how we use Tailwind for the web. Cool right?

import Header from '../components/header/index.tsx';
import Horizontal from '../components/scroller-item/Horizontal.tsx';
import Vertical from '../components/scroller-item/Vertical.tsx';
import Scroller from '../components/scroller/index.tsx';
import { blogs } from '../constants/blogs.ts';
import { categories } from '../constants/categories.ts';
import { IMAGE } from '../constants/images.ts';
const Home = () => {
return (
<>
<Header />
<view className="bg-stone-100">
<Scroller
oritentation="horizontal"
styles={{
width: 'calc(100% - 1px)',
height: '100px',
paddingBottom: '20px',
paddingTop: '20px',
paddingLeft: '12px',
paddingRight: '12px',
borderRadius: '1px',
}}
>
{categories.map((item, index) => (
<Horizontal index={index} item={item} />
))}
</Scroller>
</view>
<view className="h-full p-4">
<view className="flex justify-between items-center">
<text className="font-bold leading-normal text-2xl">Games</text>
<image src={IMAGE.ICON_FILTER} className="w-6 h-6" />
</view>
<Scroller
oritentation="vertical"
styles={{
width: 'calc(100% - 1px)',
height: 'calc(100% - 280px)',
paddingBottom: '20px',
}}
>
{blogs.map((item, index) => (
<Vertical item={item} />
))}
</Scroller>
</view>
</>
);
};
export default Home;
showcase final output blog app with lynx.js
Final Output Blog App With Lynx.js

Conclusion: IMO

After exploring Lynx.js, it’s clear this framework brings an interesting approach to web development and shines in certain areas, even currently, as I write this blog, still in beta version.

However, Lynx.js still has room to grow. Looking ahead, I hope future updates will bring:

  1. More comprehensive documentation, especially for third-party integrations
  2. Native navigation solutions beyond React-Router
  3. Streamlined library integration processes
  4. Expanded component library and styling options
  5. Better community resources and examples

Lynx.js shows promise with its web-like approach to development, but it needs continued refinement to reach its full potential. The foundation is solid, and with active development and community growth, it could become a compelling option for developers seeking performance and familiar web paradigms.

Thank you for being a part of the community

Before you go:

Leave a Reply