Skip to content
Blog

Jaspr: Dart Web Development That Renders Real DOM

Jaspr brings Flutter-style component programming to Dart web development with real HTML/CSS output, server-side rendering, and Flutter widget interop — ideal when Flutter web canvas rendering is not the right fit.

Published on • September 25, 2026

AI Assistant

Flutter web is a remarkable piece of engineering: one renderer, six platforms, pixel-perfect consistency. But it paints into a canvas, and a canvas is opaque to search engines, screen readers built for the DOM, and anyone who wants to “view source.” For app-like experiences — dashboards, tools, games — that trade is worth it. For content-heavy sites, landing pages, and anything where SEO and first-paint matter, it is the wrong tool.

That is the gap Jaspr fills. Jaspr is an open-source Dart framework for building websites where components look and feel like Flutter widgets, but the framework renders real HTML and CSS instead of painting a canvas. The current release line is jaspr: ^0.22.0, installed via jaspr_cli.

Components That Feel Like Home

If you know Flutter, you know most of Jaspr already. BuildContext, setState, stateless and stateful components — the mental model transfers directly:

class App extends StatelessComponent {
  const App({super.key});

  @override
  Component build(BuildContext context) {
    return div([
      h2([text('Everything is a Component')]),
      Button(primary: true, label: 'Try out in Playground'),
    ]);
  }
}

Stateful interaction is equally familiar:

Component build(BuildContext context) {
  return button(
    onClick: () { setState(() => count++); },
    [text('Clicked $count times')],
  );
}

Where Flutter has Column and Container, Jaspr has div, h2, section — the DOM is the widget catalog. The VS Code extension even ships quick actions for converting components to StatefulComponent or AsyncStatelessComponent, so refactoring stays ergonomic.

Rendering Modes: Static, SSR, and SPA

Jaspr’s most consequential feature is that HTML generation does not have to happen in the browser. Three rendering strategies are available, configured per app:

  • Static generation — mode: static in pubspec.yaml produces plain HTML at build time. Ideal for blogs, docs, and marketing sites: the output is as fast as hand-written HTML.
  • Server-side rendering — pages are pre-rendered on a Dart server per request, with data fetched on the server during pre-rendering and synced to the client. This is the mode for dynamic but SEO-critical sites.
  • Single-page application — classic client-side rendering when you want an app shell with no server.

Because SSR happens in Dart, your data-fetching code, models, and validation logic can be the same Dart code your Flutter app uses. The framework supports fetching data on the server during pre-rendering and hydrating the client from that state — no duplicate API round-trips.

Styling and Routing

Styling is deliberately flexible: write styles inline in Dart, adopt the Tailwind integration, or drop in any CSS-based solution you already use. There is no proprietary styling abstraction to fight; if it works on the web, it works in Jaspr.

Routing is provided by jaspr_router, described by the project as “simple yet powerful,” and — critically — the same routing system works in all three rendering modes. A route table does not need to be rewritten when you move from SPA to SSR.

The Ecosystem Play

This is where Jaspr distinguishes itself from a generic “Dart-to-JS” experiment:

  • Any pub.dev Dart package works — Riverpod, http, dart_mapper, whatever your app already depends on.
  • Flutter web plugins are supported through Jaspr’s custom compiler pipeline.
  • You can embed real Flutter widgets inside a Jaspr site. The canvas renderer becomes a component you drop in for the interactive parts, not the foundation of the whole page.
  • Dart backend integration with Shelf, Serverpod, and Dart Frog means your SSR server can be the same codebase as your API.

That last-mile design — DOM site as the chassis, embedded Flutter where richness is needed — resolves the “should this be a website or a Flutter app?” argument. It can be both, in one language, one repo.

Jaspr vs Flutter Web

The positioning is complementary rather than competitive:

Flutter webJaspr
RenderingCanvas (Skia/Impeller via CanvasKit/Wasm)Real HTML/CSS DOM
SEOPoor — content behind a canvasFirst-class — real markup, crawlable
First paintHeavier engine downloadFast, especially static/SSR
ConsistencyPixel-perfect across platformsNative web look and behavior
Best forDashboards, tools, app-like experiencesContent sites, landing pages, SEO-critical pages
Flutter widgetsNativeEmbeddable via interop

The Flutter team’s own 2026 roadmap acknowledges this split by committing to Wasm-by-default rendering for app-like experiences while linking Jaspr for web-first, DOM-based development. When your product is fundamentally a document — a blog, documentation, a marketing site — the DOM is simply the correct rendering target.

Community signals support the niche: a 500+ developer Discord, endorsements from Dart/Flutter product management (Kevin Moore) and Serverpod’s founder (Viktor Lidholt), and enterprise support options from creator @schultek.

When to Choose Jaspr

Choose Jaspr when:

  • SEO and social sharing previews are requirements, not nice-to-haves.
  • First-contentful-paint budgets are aggressive (static or SSR modes).
  • The site is content-first with islands of interactivity.
  • You want one language across marketing site, backend (Dart Frog/Serverpod/Shelf), and mobile app (Flutter) — with shared models and business logic.
  • You need Flutter interop without committing the whole page to the canvas renderer.

Stick with Flutter web when the product is an application — dense dashboards, editors, anything where platform-consistent custom UI is the point. And remember the hybrid: Jaspr page with an embedded Flutter module is a supported, first-class path.

Getting Started

dart pub global activate jaspr_cli
jaspr create my_site

The generated project includes the rendering-mode configuration in pubspec.yaml, so switching from SPA to static or SSR later is a configuration change, not a rewrite. The official site’s playground lets you try components in the browser before installing anything.

Summary

Jaspr completes the full-stack Dart story on the web. Where Flutter web optimizes for app-like fidelity, Jaspr optimizes for the document web: crawlable markup, server rendering, fast loads, and a component model that Flutter developers already understand. With Flutter widget interop for the rich bits and pub.dev compatibility for everything else, choosing between “website” and “Flutter app” is no longer forced — 2026’s Dart ecosystem lets one codebase be both.

References