LynxJS is a write-once-run-anywhere framework for developing mobile and web applications using TypeScript.
This tutorial project is part of a workshop that we hosted at the WeAreDevelopers World Congress in July 2025.
Lynx: From Zero to Native workshop
This app helps the user plan a regular stream of communications such as internal team announcements or social media posts: When you think of an idea, you create a "remark" which is initially in the "NOT READY" bucket. Once you've refined your idea, you move it to the "READY" bucket, which represents a backlog of ready-to-post ideas. Then you can assign them to calendar days over the next week. (For simplicity, instead of a full calendar, the UX simply tracks the next 7 days.) After a remark has been posted, you move it to the "ARCHIVED" bucket.
This tutorial introduces the following Lynx features:
- Creating a project from scratch using Rspeedy
- Basic React functional components without reliance on any opinionated frameworks
- A self-contained store that works with
useSyncExternalStore()
- Usage of
react-router
- Common elements:
<view>
,<text>
,<scroll-view>
,<textarea>
,<input>
- CSS variables
- Some CSS techniques such as
box-shadow
- Layouts:
grid
,flex
,linear
MainPage.tsx screenshot
EditPage.tsx screenshot
The tutorial steps are tracked as commits to the main
branch of this repo. Each commit has a Git tag for easy access.
# Example: check out step #6
git checkout tags/step-6
# If you want to discard your local changes:
# BE CAREFUL
git reset --hard
step-1
: pnpm create rspeedy@lateststep-2
: Update prettier configstep-3
:prettier -w .
step-4
: Add some deps and settingsstep-5
: pnpm installstep-6
: Add<input>
and<textarea>
typings from Lynx dev branchstep-7
: Initial sketch of Button and MainPage componentsstep-8
: Define CSS variables for colorsstep-9
: Touching highlights the buttonstep-10
: Add onClickstep-11
: Initial sketch of ListBox componentstep-12
: Add border and shadowstep-13
: Introduce a minimalist subscribeCallback() to power useSyncExternalStore()step-14
: Create a basic AppModel containing a list of RemarkModel items, and tracking a selectedItemstep-15
: Wire up the modelstep-16
: Add useSyncExternalStore() subscriptionstep-17
: Implement the "New..." buttonstep-18
: Introduce BucketId and selectedBucketIdstep-19
: Add Bucket componentstep-20
: Add "Archived" bucketstep-21
: Filter listbox to show selectedBucketIdstep-22
: Buckets show item countstep-23
: Add "Edit" and "Move" context itemsstep-24
: Implement "Move" buttonstep-25
: Add EditPagestep-26
: Add global styles for<input>
and<textarea>
step-27
: Add a router and navigationstep-28
: Implement "Delete" buttonstep-29
: Add Calendar component
The EditPage.tsx relies on new <input>
and <textarea>
features from Lynx that have not been officially released yet. As of July 2025, to use them with LynxExplorer, you will need to build it from the development branch. (Otherwise, the demo will work, but the EditPage will not render correctly.)
If you don't have native build tools, a prebuilt APK for Android is provided here. Or you can wait for the next official release of Lynx. Nightly snapshot builds will be available soon for Lynx as well.