DEV Community

Cover image for I Got Tired of Maintaining Frontend Code. So I Built a Declarative UI Runtime.

I Got Tired of Maintaining Frontend Code. So I Built a Declarative UI Runtime.

Thuangf45 on July 10, 2026

Here is a question that sounds simple until you've actually shipped a UI: how many files does it take before nobody on the team, including you, can...
Collapse
 
abudanov profile image
Aleksandr Budanov

Groundbreaking stuff. Next week, let's replace JSON with YAML and call it a new paradigm. You literally just traded <Component/> for {"type": "Component"} and swept the naming chaos under the rug. This doesn't fix the underlying issues, it just wraps them in a worse developer experience.

Collapse
 
thuangf45 profile image
Thuangf45

If all I had done was change the syntax, I'd agree with you. The runtime is the point, not JSON.

Out of curiosity, how many files and how much setup do you need to go from an empty folder to a working payment button with real behavior? Mine starts with two files and no build step.

More importantly, what happens when that button has a bug in production? In my runtime I can override or disable its behavior by changing a single action in content.json, or even replace the UI entirely, without rebuilding or redeploying the application. The runtime picks up the new description immediately. That's the trade-off I'm exploring: moving common UI behavior from implementation into declarative data.

Collapse
 
miketalbot profile image
Mike Talbot ⭐

I agree, YAML has many advantages over JSON for human-written code and would fit here.

Collapse
 
abudanov profile image
Aleksandr Budanov

Are you kidding? It was sarcasm.

Thread Thread
 
miketalbot profile image
Mike Talbot ⭐

No - I understand you were being sarcastic; I wasn't :)

Collapse
 
chris_devto profile image
Chris

😁 This.

Collapse
 
thuangf45 profile image
Thuangf45

Thanks for reading! Just to clarify one point that isn't obvious from the article: LuciaCore isn't trying to replace HTML, CSS, or JavaScript. They're still the execution layer. The runtime simply moves developers one level higher, from describing implementation to describing intent.

Collapse
 
chris_devto profile image
Chris • Edited

From my POV the problem you're describing is solved by a Design System, Governance and QA not by reinventing the wheel. If you have a Design System with a button, all parts of the system consume this. This way it's all consistent and updates get cascaded. This solution just adds more complexity and doesn't scale, as you're asking Developers to change the way they work by learning some random JSON syntax.

Collapse
 
thuangf45 profile image
Thuangf45

That's a fair point. I don't think LuciaCore replaces Design Systems, governance, or QA. Those are proven solutions, especially for large organizations.

The problem I was trying to solve is different. Design Systems still rely on people following conventions correctly. LuciaCore moves part of that responsibility into the runtime, so rendering and behavior are standardized by construction rather than primarily by process.

My target audience is also different. It's aimed at solo developers, small teams, and even non-technical collaborators who don't have dedicated design system teams or complex delivery pipelines. Starting from an empty folder, they only need index.html and content.json to build a working interactive UI.

Regarding the "random JSON syntax" point, I don't really see it as introducing another language. The vocabulary is intentionally small: type, style, action, props, and a few related concepts. The runtime understands those concepts and generates the implementation consistently. JSON is simply the serialization format, not the idea itself.

There's also a trade-off around ownership. Large organizations often solve consistency through people, reviews, governance, and process. That works well at scale, but it also naturally distributes knowledge across many contributors. What I'm exploring is the opposite end of that trade-off: making the entire UI description compact enough that one person, a small team, or even an AI assistant can reason about the whole application without reconstructing relationships across hundreds of implementation files.

Operational flexibility is another reason I built it this way. If I discover a production issue in a button, I can override or disable its declarative action by updating content.json, without rebuilding the application. The runtime immediately interprets the new description. That obviously isn't the right trade-off for every project, but it's the one I wanted to explore.

So I don't see LuciaCore as replacing existing frontend ecosystems. It's an experiment in solving the same consistency problem from a different direction: using a runtime to encode conventions that would otherwise depend on organizational process.

Collapse
 
chris_devto profile image
Chris • Edited

Design Systems still rely on people following conventions correctly.

Yup, the same way LuciaCore requires Devs to follow different conventions, it shifts the responsibility for no reason.

My target audience is also different. It's aimed at solo developers, small teams, and even non-technical collaborators who don't have dedicated design system teams or complex delivery pipelines.

But smaller teams don’t need this then, they can just unify something like a button without the need for a new system.

Regarding the "random JSON syntax" point, I don't really see it as introducing another language. The vocabulary is intentionally small: type, style, action, props, and a few related concepts. The runtime understands those concepts and generates the implementation consistently. JSON is simply the serialization format, not the idea itself.

But you’re asking WebDevs to now build in JSON rather than standard WebComponents or JS framework components - why?

making the entire UI description compact enough that one person, a small team, or even an AI assistant can reason about the whole application without reconstructing relationships across hundreds of implementation files.

But it’s not needed then in this context, eg with a button - here’s the file. Use this. Smaller team can just ensure they share components.

Operational flexibility is another reason I built it this way. If I discover a production issue in a button, I can override or disable its declarative action by updating content.json,

That’s what a shared Components does. It’s shared so the controller can do this without a json file

It's an experiment in solving the same consistency problem from a different direction

This particular problem has been resolved with a different industry standard. However experiments can be fun - I hope you had a great learning from it!

Thread Thread
 
thuangf45 profile image
Thuangf45

That's a fair point, and I agree that Design Systems, governance, and QA are proven solutions for large organizations.

The problem I'm exploring is different. A Design System standardizes reusable components. LuciaCore standardizes how the entire UI is described and executed. The runtime owns rendering, layouts, routing, actions, component resolution, content separation, and compiled-page caching as a single declarative system. That's a different abstraction level.

Regarding the "random JSON syntax" point, I don't really see it as introducing another language. The vocabulary is intentionally small: type, style, action, props, and a few related concepts. JSON is simply the serialization format. The runtime is the idea.

One clarification on the production-update point: a shared component still lives in source code. Changing its behavior still means changing the implementation and shipping a new build before users receive the update. LuciaCore interprets content.json directly at runtime. There is no compile step between the description and execution. That's not just "components written as JSON." It's a different execution model.

For very small projects, I agree that sharing a button component may be enough. LuciaCore isn't trying to optimize that single use case. It's exploring whether one person, a small team, or even a non-technical collaborator can own an entire interactive application through a single declarative description without introducing build tooling or deployment friction.

If your workflow is already optimized around React, a mature Design System, and a large engineering organization, then LuciaCore is probably not the right trade-off. That's completely fine. The project exists to explore a different set of trade-offs, not to replace the existing frontend ecosystem.

Collapse
 
johndoedev profile image
Johndoe

Really interesting read. My biggest question would be scalability. Once an application grows to hundreds of screens and thousands of nodes, does the JSON stay manageable, or do you end up recreating the same complexity in another format?

Collapse
 
thuangf45 profile image
Thuangf45

Great question. My current approach is to avoid repeating large JSON trees in the first place. Most UIs are composed from reusable components, so even if a page contains a thousand buttons, it's usually a thousand references to the same component or primitive rather than a thousand independent definitions.

There's also an item: mechanism alongside props:. While props: maps one-to-one, item: lets a component render one-to-many through iteration. In practice, that means a list of hundreds of similar elements can often be expressed as a single component plus a data collection instead of hundreds of repeated nodes. Of course, this only works well when those elements actually share the same structure, which is usually the case for tables, menus, cards, product lists, and similar UI patterns.

Collapse
 
lan_nguyn_47e34db57c8a55 profile image
Lan Nguyễn

I appreciate that you repeatedly call it a prototype instead of claiming it's going to replace React or Vue. That's a much more credible position. Even if I wouldn't use it today, the DSL design itself is worth reading.

Collapse
 
thuangf45 profile image
Thuangf45

Thanks, I appreciate that. I think it's healthier to present it as an experiment with a different set of trade-offs than as "the next React killer." Even if the overall approach doesn't fit every project, I hope some of the ideas around declarative UI description and standardized rendering are useful to discuss.

Collapse
 
manolito99 profile image
Lolo

I like that the judging includes writing quality, not just the final project. Some of the most interesting engineering decisions are hidden unless people explain why they built something a certain way.

Collapse
 
thuangf45 profile image
Thuangf45

Thanks! That was actually one of my goals with this article. The implementation itself only tells part of the story. The interesting part, at least to me, is explaining the reasoning and trade-offs behind each design decision.

Collapse
 
michelle_harrison_9638821 profile image
Michelle Harrison

So make your own Language
Why put limits on your work. People wonder why I don't put any effort into getting my udebtyn back or my life

Collapse
 
thuangf45 profile image
Thuangf45

Thanks for reading!

Collapse
 
thuangf45 profile image
Thuangf45

I'm treating this as an experiment rather than "the next framework". If you see architectural weaknesses or edge cases where this approach would break down, I'd genuinely like to hear them. That's much more valuable than people simply saying it's interesting.

Collapse
 
thuangf45 profile image
Thuangf45

One thing I couldn't fit into the article is that the action system ended up growing into a small declarative DSL. Besides navigation and API calls, it already supports conditions, pipelines, storage, custom modules, and arbitrary JavaScript execution when needed. The goal wasn't to remove flexibility, but to make the common path much more consistent.

Collapse
 
buffermodeler profile image
BufferModeler

This reminds me a little of the declarative ideas behind Flutter or SwiftUI, except you're describing everything with JSON and letting the runtime own the implementation. Interesting direction.

Collapse
 
thuangf45 profile image
Thuangf45

Thanks! I actually drew inspiration from the same general idea of describing UI declaratively, but I wanted to explore a different trade-off. Instead of building another component framework, I wondered how far a small runtime plus a constrained declarative language could go while keeping the browser as the only execution environment.

Collapse
 
wrencalloway profile image
Wren Calloway

@thuangf45 The customButton-plus-props approach is a real answer to the variant question, and it's a better one than I gave you credit for — you're betting on one stable identity plus local overrides instead of a fixed enum, and for domains that don't cleave neatly into primary/secondary/danger that's the more honest model. Fair.

But watch where the drift actually lands with props:style. The cascade appends caller CSS last, so overrides work — right up until two screens both need "the same variation." Now that visual delta lives inline at two call sites, and you're back to the exact copy-or-reference fork, just pushed down one level from the component to the override string. The enum wasn't the point; enforced reuse was. If props:style is freely typeable, nothing stops the second caller from retyping the first caller's override, and there's no mechanism that notices they're now the same thing wanting to be a name. That's the seam I'd instrument.

On the action DSL I think you're on solid ground — sequencing plus a branch plus a module contract is a genuinely closed vocabulary, and pushing domain behavior into modules-implementing-a-contract is the right call. My worry evaporates as long as the branch condition itself stays dumb. The day condition needs to parse something richer than "call a module and read a boolean" is the day the grammar starts growing whether you meant it to or not. Keep that predicate a module call and I think you've actually closed the escape hatch I was pointing at.

Collapse
 
thuangf45 profile image
Thuangf45

That's a really thoughtful review, and I appreciate you taking the time to dig into the design instead of stopping at the JSON example.

I also think you're right about where drift can move. Today, props:style is intentionally an escape hatch. If the same override starts appearing repeatedly, that's a signal it should become part of the shared component instead of remaining inline. The runtime doesn't detect that today.

LuciaCore is still very much a prototype. My first goal was simply to prove that a declarative runtime could describe and execute a real interactive application directly from JSON, without a build step. Before investing in tooling, I wanted to validate that the architecture itself was practical.

If the community finds those capabilities genuinely useful, I'd be happy to add them as optional, schema-configurable features. Projects could enable or disable policies, warnings, or other architectural checks without changing the core execution model.

I also agree with your point about the action DSL. Keeping the vocabulary closed is a deliberate design goal. Even conditions are intentionally limited to a single level—they don't nest or grow into another programming language within the declarative runtime. If multiple checks are needed, they're composed as a pipeline rather than building larger boolean expressions. The runtime remains responsible only for sequencing, branching, and invoking modules; all domain-specific logic stays inside those modules.

So I don't disagree with your observation at all. I see it less as a flaw in the execution model and more as a tooling problem that sits one layer above it. If the project proves useful, those are exactly the kinds of capabilities I'd like to build next.

Collapse
 
alexshev profile image
Alex Shev

The interesting part of declarative UI runtimes is not fewer files by itself; it is moving the change surface closer to the product concept. If the runtime makes the common product edits smaller without hiding escape hatches, that is a real architecture win. If it only moves complexity into a schema, the pain comes back later.

Collapse
 
thuangf45 profile image
Thuangf45

Thanks, I think that's a good way to frame it.

That's exactly the trade-off I'm exploring. The goal isn't just fewer files, but keeping the declarative surface growing much more slowly than the product itself.

I separate the system into three concerns:

  • Components define reusable UI structures.
  • Contents provide the data for those structures (labels, icons, actions, etc.).
  • Pages compose them into screens.

Once the components stabilize, they grow very slowly because they're reused everywhere.

Large datasets don't expand the schema either. A product grid with 10 items and one with 100,000 items use the same declarative description. The runtime binds API data through loops instead of requiring the schema to enumerate every item.

So I'm trying to keep the declarative description proportional to the UI structure, not to the amount of business data. And when something genuinely falls outside the model—complex effects or specialized business logic—I simply call JavaScript. I'd rather keep the common 95% declarative than force 100% into the runtime.

Collapse
 
alexshev profile image
Alex Shev

That proportionality test is strong: the description should grow with the structure of the UI, not with every implementation detail. A declarative layer earns its place when common product edits stay small, while the escape hatch remains clear enough for the weird cases.

Collapse
 
unitbuilds profile image
UnitBuilds

Interesting, you basically ran into a same frustration I did, except you just handled the frontend. I got pissed off enough to overhaul everything 😅 V.A.L.I.D.

Collapse
 
thuangf45 profile image
Thuangf45

That's an interesting direction. It feels like we're optimizing different bottlenecks.

V.A.L.I.D. pushes performance by optimizing the execution model inside Blazor, while LuciaCore tries to reduce the amount of implementation people have to write in the first place.

My primary goal isn't to squeeze another few nanoseconds out of rendering—it's to make common UI changes possible without rebuilding the application, and to keep the UI description simple enough that even non-developers can modify it safely. Performance still matters, but reducing cognitive complexity is the first constraint.

Collapse
 
unitbuilds profile image
UnitBuilds

Not quite, V.A.L.I.D. handles pretty much the full-stack. I used it for my accounting suite (500k LOC), 82% of that is generated by V.A.L.I.D. that includes front and backend code, including Unit tests, MCP, BOs, DALs, UI-linkage, etc. including wiring the V.A.V.I.D. HUD for UI fuzzy testing, all while getting a 6x performance boost over standard Blazor, by entirely ditching the VDOM, in favor of unmanaged slabs. It makes the 'cognitive complexity' as simple as it gets, you just say what UI element you want, eg. a button and in the dto, you say what are your constraints for it and what rules you want it to adhere to. That's it, everything else is generated and any adjustments you make propagate across the entire codebase at compile time, so 99% of errors surface before you even run it.

Thread Thread
 
thuangf45 profile image
Thuangf45

That's impressive. It sounds like we're reducing complexity from opposite directions.

V.A.L.I.D. minimizes the amount of handwritten code by generating it at compile time. LuciaCore minimizes the amount of code that needs to exist at all for common UI changes by interpreting a declarative description at runtime.

For me, the key trade-off is operational rather than computational. If a label, layout, workflow, or button behavior needs to change, I want that change to be possible by updating the UI description without producing a new build.

So I don't really see the two ideas as competing. V.A.L.I.D. optimizes the compile-time developer workflow, while LuciaCore explores whether a large class of UI changes can move out of the compile/deploy cycle entirely.

We're both trying to reduce cognitive complexity, just at different stages of the software lifecycle.

Thread Thread
 
unitbuilds profile image
UnitBuilds

It does the UI too, by ditching the VDOM entirely, opting for unmanaged slabs, so essentially 128 bits that map directly to the backend variables. So no massive HTML, just 128 bits. Because they're unmanaged slabs, technically live-updating without needing to build should be possible

Collapse
 
wrencalloway profile image
Wren Calloway

The inline style in your JSON example is the tell that this hasn't hit its real test yet. "style": "background: #2563eb; ..." is exactly the hand-assembled, drift-prone implementation detail you set out to kill — you've just moved it from a CSS file into a string inside a JSON node. The moment a second button wants the same look, you either copy that string (drift is back) or you invent a way to reference a shared token, at which point you've reinvented CSS classes with more steps. The inconsistency you fought wasn't caused by HTML/CSS/JS being separate files; it was caused by there being no single source of truth for "what a primary button is." JSON-as-data doesn't give you that source of truth for free — it just relocates where you're allowed to be inconsistent.

The thing that actually saved teams from your 200-file problem historically wasn't declarative-vs-imperative, it was constraint: a design system with a fixed vocabulary of variants, enforced so background: #2563eb literally cannot be typed inline. That's where I'd push LuciaCore next — not "describe any button as data" but "you may only reference primary, secondary, danger." Freedom to inline arbitrary style is the same footgun that gave you three different buttons the first time; a runtime that permits it will drift the same way, just in a new file extension.

One concrete failure mode to watch: action: "navigate::to::signup" is a tiny DSL, and DSLs grow. The first time someone needs a click that navigates and fires analytics and is conditional on auth state, that string either sprouts a grammar or you punt back to raw JS — and the escape hatch is exactly where the "same way every time" guarantee quietly dies.

Collapse
 
thuangf45 profile image
Thuangf45

That's a thoughtful critique, and I actually agree with the underlying concern. If a declarative runtime simply moves inconsistency into another format, it hasn't really solved anything.

You're also right that the runtime currently allows inline styles as an escape hatch. Nothing prevents someone from styling a primitive directly instead of composing a reusable component. I don't consider that problem completely solved. The goal is to make reusable components the natural path so the surface where inconsistency can appear becomes much smaller, while still keeping an escape hatch for the uncommon cases.

That's also why I intentionally avoid modeling every component as fixed variants like primary, secondary, or danger. Those abstractions work well in many design systems, but they don't always map naturally to every domain.

Instead, I try to keep the component identity stable. A project might expose a single customButton component that everyone references, rather than gradually accumulating submitButton, loginButton, actionButton, and other near-duplicates. When a screen needs a small visual variation, it extends the shared component through props instead of creating another component with a new identity. Mechanically, the component's default style ends with a props:style placeholder, so caller-supplied CSS is appended last and overrides only the declarations it explicitly sets through normal CSS cascade rules. The runtime doesn't need any special style-merging logic. The default implementation stays shared, while customization remains local to the specific use case.

On the action DSL, I think the concern would be valid if the language kept growing. I deliberately keep the runtime vocabulary very small. The runtime understands sequencing (|>), conditional branching (condition ?=> actionIfTrue :=> actionIfFalse), a small set of system calls, and the execution contract for external modules. It doesn't need to understand analytics, payments, authentication, or any other domain-specific behavior. Those are simply modules that implement the contract, while the runtime only orchestrates execution.

So if a button needs to check authentication, fire analytics, and then navigate, that's composed from existing primitives instead of extending the language with another keyword or grammar rule.

Ultimately, that's the trade-off I'm exploring. The declarative layer stays focused on describing UI structure and common interaction patterns. Domain-specific complexity lives in reusable modules, while visual variations extend shared components instead of creating new identities. The runtime provides the execution model; JSON is simply the serialization format that describes it.

Collapse
 
marouaneks profile image
Marouane K

Hi thuangf45, I saw your post on declarative UI runtime. I'm curious, are you struggling to manage frontend code complexity? Clypify can help you automate content creation and distribution to WordPress and Medium. Free plan at clypify.com — no card needed.

Collapse
 
evans_owusu_6801c8d54ae89 profile image
Evans Owusu

Declarative UI runtime" is doing a lot of work in that title, so curious how far you took it — is this closer to a config/JSON-driven renderer (like a schema that maps to components), or something deeper where the runtime itself interprets state transitions and layout without a build step at all?
The maintenance pain with frontend code usually comes from one of a few places: prop-drilling and state sync across components, the coupling between business logic and rendering, or just the sheer number of ways to express the same UI (three different button variants because nobody remembered the first one existed). Which of those was the actual trigger for building this, versus something more structural like wanting hot-swappable UIs driven by server-side config?
Also curious about the tradeoffs you hit — declarative runtimes tend to buy you consistency and less boilerplate, but often cost you escape hatches for one-off custom behavior. How are you handling the "I need this one screen to just do something weird" case without it turning into an imperative escape valve that undermines the whole model?

Collapse
 
thuangf45 profile image
Thuangf45

Great questions.

It's closer to the second description than the first. I wouldn't describe LuciaCore as a JSON-driven component renderer where a schema simply maps to existing components. The runtime is the execution model: it resolves layouts, component composition, data bindings (props, item, content, api), navigation, actions, and rendering directly from the description, without a build step between the UI description and execution.

The original trigger was mostly consistency rather than hot-swappable UIs. I kept running into the same problems: too many ways to express the same screen, components gradually diverging, and understanding behavior requiring jumps across many implementation files.

That consistency problem ended up solving a second problem almost by accident: once UI is described as data instead of source code, it also becomes swappable at runtime without a build step.

On state, I don't have a separate state-management layer like React or Vue. State naturally flows through props, item, content, and api bindings. For example, navigating to a product page passes the selected product id as props:id; the destination resolves that into an API query, receives data, maps it back into props, and re-renders. The runtime is interpreting data flow rather than explicit reducers or mutable component state.

The vocabulary is intentionally small (button, text, row, column, props, item, api, etc.). Components expose their entire contract through props, so opening a component is usually enough to understand what it expects without tracing implicit bindings across many implementation files. One of the motivations was to reduce the number of subtly different UI abstractions that naturally appear as projects grow.

As for escape hatches, they're still there. Actions can invoke JavaScript when needed, so I'm not trying to eliminate imperative code completely. The goal is simply to keep the common 95% declarative and reserve imperative code for the genuinely unusual cases instead of making it the default.

Collapse
 
alexshev profile image
Alex Shev

The interesting part is that declarative UI only pays off if the runtime owns enough of the boring contract: state transitions, validation, rendering boundaries, and failure modes. Otherwise it just moves complexity from components into configuration. The win is not fewer files by itself; it is fewer places where product intent can drift.

Collapse
 
thuangf45 profile image
Thuangf45

Agreed — that's the bar I'm designing against. The runtime owns enough of that boring contract that the schema doesn't need to compensate: what you describe is what executes, nothing more, nothing implicit. That's what keeps it from just becoming complexity relocated into configuration.

The part I care about most is where behavior lives. An action or a state change happens at the place it's declared, not somewhere else it gets triggered from. That's what actually limits drift — not fewer files, but fewer places to go looking when something behaves unexpectedly.

It even shows up in debugging. Since the pipeline is just a declared sequence, every step has access to the execution context—built-in values like prev, result, action, id, as well as any context a module chooses to expose. I can temporarily insert console::log::${...} anywhere in the pipeline to inspect exactly what that point sees, without opening modules or rebuilding the application. When I'm done, I remove that single step. Because the pipeline and its context are just data, observing them is simply another declarative action.

Collapse
 
mudassirworks profile image
Mudassir Khan

the 'nothing in those two hundred files agreed about how a button should be built' line is the one. we hit the same wall around 150 components. inconsistency, not complexity, was the actual cost.

what helped wasn't yet another component abstraction: making the schema the unit of review. once you're looking at a config object in a PR diff instead of a JSX tree, the noise drops and regressions become visible.

curious how LuciaCore handles state that isn't purely in the data — things like hover effects, user triggered transitions, or optimistic updates. does that live in the schema or does it need a separate behavior layer?

Collapse
 
thuangf45 profile image
Thuangf45

The PR review point especially resonates with me. That was one of the side effects I didn't fully appreciate until I started using the runtime myself. Reviewing a declarative schema usually means there's much less implementation noise to mentally reconstruct before you can see what actually changed.

On the state question, I actually think there are two different kinds of state.

Local state is carried with the interaction itself. Every rendered element already knows its own context through its dataset (for example data-id, data-action, etc.). When an action fires, those values are mapped directly into props for the next step. So if a user clicks a product, dataset.id automatically becomes props.id, and the destination page can bind that into an API call like:

GET /v1/api/product?id={props.id}

The runtime resolves the flow by passing context between actions rather than maintaining a long-lived client-side store.

Global state is different. Things like authentication, user preferences, or shopping carts can live wherever they're most appropriate—localStorage, sessionStorage, cookies, caches, or another storage layer. The schema simply composes actions to retrieve and use them. For example:

storage::get::authToken |> api::call

The retrieved value becomes part of the current execution context and can flow into subsequent actions.

For things like hover, active, focus, media queries, or simple transitions, I don't really consider those application state. They're simply CSS behavior. Styles can be declared inline on the node, including pseudo-classes and responsive rules. If they become large or shared across many components, they can be extracted into reusable style modules. The same principle applies: keep the common case compact, and only introduce another abstraction when it actually reduces complexity.

For genuinely imperative cases like optimistic updates, complex animations, or highly specialized interactions, I don't try to force everything into the schema. That's where JavaScript modules come in through a simple contract (render() or execute()). The runtime is meant to keep the common path declarative while leaving an escape hatch for the cases where imperative code is the better tool.

Collapse
 
algorhymer profile image
algorhymer

Yeah yeah yeah

Collapse
 
humanizeaitext1 profile image
Humanize AI Text

Thanks

Collapse
 
akku_new_41906f51a22c00e2 profile image
Akku New

Good

Collapse
 
thuangf45 profile image
Thuangf45

Thanks