Arcane Jaspr gives Jaspr apps a Flutter-first UI surface. Use familiar Dart widget structure, keep semantic HTML output, and only drop to HTML or raw Jaspr when you explicitly choose to.
dependencies:
arcane_jaspr: ^3.3.0
arcane_jaspr_shadcn: ^3.3.0
arcane_jaspr_neon: ^3.3.0
arcane_jaspr_neubrutalism: ^3.3.0arcane_jaspr is the core package. Add one or more renderer packages
(arcane_jaspr_shadcn, arcane_jaspr_neon, arcane_jaspr_neubrutalism) for the
themes you want; pick a stylesheet from one of them at runtime.
From the arcane_jaspr package root, serve the demo/docs app with:
dart run arcane_jaspr:serveIt serves at http://localhost:8080 and replaces any previous Arcane Jaspr demo process using that port.
Build the same demo with:
dart run arcane_jaspr:serve buildUse the primary import for normal app code:
import 'package:arcane_jaspr/arcane_jaspr.dart';
import 'package:arcane_jaspr_neon/arcane_jaspr_neon.dart';
import 'package:arcane_jaspr_shadcn/arcane_jaspr_shadcn.dart';
const ArcaneStylesheet shadcnStylesheet = ShadcnStylesheet(
theme: ShadcnTheme.midnight,
);
const ArcaneStylesheet neonStylesheet = NeonStylesheet(
theme: NeonTheme.green,
);
const ArcaneStylesheet selectedStylesheet = shadcnStylesheet;Only reach for the advanced layers when you need them:
import 'package:arcane_jaspr/html.dart';
import 'package:arcane_jaspr/web.dart';import 'package:arcane_jaspr/arcane_jaspr.dart';
import 'package:arcane_jaspr_neon/arcane_jaspr_neon.dart';
import 'package:arcane_jaspr_shadcn/arcane_jaspr_shadcn.dart';
class App extends StatefulWidget {
const App({super.key});
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
int _count = 0;
void _increment() {
setState(() => _count += 1);
}
@override
Widget build(BuildContext context) {
return ArcaneApp(
stylesheet: selectedStylesheet,
brightness: Brightness.dark,
home: ArcaneScaffold(
title: 'Counter',
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
gap: 16,
children: [
Text.heading2('Count: $_count'),
Button.primary(
label: 'Increment',
onPressed: _increment,
),
],
),
),
),
);
}
}TextInput(
label: 'Email',
placeholder: 'you@example.com',
type: TextInputType.email,
)
ArcaneCombobox(
value: 'jaspr',
options: const [
ComboboxOption(value: 'jaspr', label: 'Jaspr'),
ComboboxOption(value: 'flutter', label: 'Flutter'),
],
onChanged: (String? value) {},
)
ArcaneMenubar(
menus: const [
ArcaneMenubarMenu(
label: 'File',
items: [MenuItemAction(label: 'New')],
),
],
)Widget,StatelessWidget,StatefulWidget,State,BuildContext, andrunAppArcaneApp, neutral renderer contracts, adaptive layout contracts, and theme provider access- Arcane widgets for layout, input, menus, dialogs, data display, adaptive scaffolds, and theming
- Type-safe styling through
ArcaneStyleData
package:arcane_jaspr/html.dart contains the low-level HTML wrapper layer such as ArcaneDiv, ArcaneLabel, ArcaneLink, tables, lists, and SVG helpers.
package:arcane_jaspr/web.dart exposes raw Jaspr and DOM escape hatches.
Arcane Jaspr has two distinct interactivity mechanisms. Choosing the right one matters for static / server-rendered output:
- Declarative
ArcaneInteractionactions (passed viaaction:) are encoded intodata-arcane-*attributes (for exampledata-arcane-action) and executed by the embedded JavaScript runtime that ships with the app. These work in fully static and server-rendered HTML, with no Jaspr client hydration required. This is the SSR-safe path. Use theArcaneInteractionfactories such asArcaneInteraction.openDialog(...),.navigate(...),.copy(...),.toggleThemeMode, and.submitForm(...). - Dart callbacks like
onPressed/onChangedare wired as Jaspr event handlers and only fire when the app runs with Jaspr client hydration. In a purely static build,onPresseddoes nothing because there is no Dart event listener attached.
In short: if you need behavior in static output, use action:; reserve
onPressed / onChanged for hydrated client apps.
The interactivity runtime is injected as a single inline <script> element
(ArcaneScriptsComponent in lib/util/interactivity/arcane_scripts.dart, rendered
from lib/component/support/app.dart when includeFallbackScripts is true, which is
the default). Because the runtime is emitted inline rather than as an external file,
a strict Content-Security-Policy must allow inline scripts (for example
script-src 'self' 'unsafe-inline'). There is currently no built-in nonce hook on
the injected script, so CSP nonces are not yet supported out of the box. If you need
strict CSP, set includeFallbackScripts: false on ArcaneApp and provide the
runtime yourself through a CSP-compatible mechanism.
- Package docs: arcanearts.github.io/arcane_jaspr
- Docs/demo app:
arcane_jaspr_docs/arcane_jaspr_docs_web - Generated component catalog:
arcane_jaspr_docs/arcane_jaspr_docs_web/content/docs/components-catalog.md
GNU Public