nativelayout
Write the screen once. Get real native views.
Ready to build native interfaces from a plain text file? No WebView, no canvas: a .nl file written in HTML becomes the buttons, fields and lists of the platform. Choose from the following options to get started.
Quick start
RecommendedOpen the online editor, write a .nl screen and see the live preview in your browser.
Custom setup
Add the JitPack repository and both artifacts to your own Android project.
Specification
The full language: tags, style, values, the program side and errors.
Examples
A runnable tasks app with forms, lists, filters and on-device storage.
How it works
A screen is one text file: HTML you already know, plus three additions. {value}, if / for lines, and a style with simple selectors. The logic stays in your language, in a screen function.
<nativelayout>
<link rel="stylesheet" href="tasks.css">
<body>
<header>
<img id="back" src="icon:arrow-left">
<h1>Tasks</h1>
</header>
if pending == 0:
<p>Nothing to do.</p>
else:
<p>{pending} pending</p>
end
<input id="title" placeholder="New task">
<button id="add">Add</button>
for task in tasks:
<div class="card" key="{task.id}">
<p>{task.title}</p>
</div>
end
</body>
</nativelayout>// one function holds the state and the taps
fun NativeView.TasksScreen(): Page {
val s = state { mutableMapOf<String, Any?>(
"pending" to 2, "tasks" to loadTasks()) }
if (click("add")) {
addTask(s, value("title"))
setValue("title", "")
}
if (click(".card")) {
toggleTask(s, clickIndex())
}
return view("tasks.nl", s)
}Features
Styling
Style it like CSS: variables, pressed states, gradients, shadows and a dark theme, in a plain .css file linked from the screen.
:root { --bg: #F2F2F2; --card: #EDE9FE; --accent: #2F81F7; }
/* dark theme */
@media (prefers-color-scheme: dark) {
:root { --bg: #0F172A; --card: #1E293B; }
}
body { background: var(--bg); padding: 1.25rem; gap: 1rem; }
.card { background: var(--card); border-radius: 0.75rem;
padding: 0.875rem; box-shadow: 0 2px 4px #0003; }
#add { background: var(--accent); color: #FFFFFF; font-weight: bold; }
#add:pressed { background: #1F6FE0; }<!-- only items on screen become views --> <div virtual style="gap: 0.5rem"> for p in products: <div class="item" key="{p.id}"> <p class="name">{p.name}</p> <p class="price">{p.price}</p> </div> end </div>
Targets
One file, any language. Each language supplies an Expander, an Engine and a native host. The .nl file stays the same.
Python lives in the python/ folder. Want to add a language? See the contributing guide.
Install on Android
Published through JitPack. Add both artifacts with the same version. Minimum SDK 21.
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven("https://jitpack.io")
}
}dependencies {
implementation("com.github.getnativelayout.nativelayout:nativelayout-android:v1.2.0")
implementation("com.github.getnativelayout.nativelayout:nativelayout-core:v1.2.0")
}To try a screen without creating a project, open the online editor. It has code, data and a live preview, and nothing to install.
Read the article
The motivation, the proposal and the first results on long lists are described in the technical article: Rafael, A. C. (2026). Describing Native Android Interfaces with HTML and CSS: A Proposal for Simplification. Zenodo. doi.org/10.5281/zenodo.23470439
Unless stated otherwise, the documentation on this site reflects nativelayout 1.2.0. View source or report an issue.