Arcane Jaspr

A Jaspr web framework port of the Arcane UI component library. Build beautiful web applications with Dart using familiar Arcane patterns.

Overview

Arcane Jaspr brings the Arcane UI design system to the web via Jaspr. It provides a comprehensive set of pre-styled, composable components that render to semantic HTML with CSS styling.

Key Differences from Flutter Arcane

  • HTML/CSS Output: Components render to actual HTML elements with CSS, not Flutter widgets
  • No Fragment Shaders: Visual effects use CSS filters, gradients, and animations instead of GLSL shaders
  • CSS-Based Theming: Uses CSS custom properties and the Styles class for theming
  • Server-Side Rendering: Full SSR support with automatic hydration

Installation

Add to your pubspec.yaml:

dependencies:
  arcane_jaspr: ^0.0.1

Quick Start

import 'package:arcane_jaspr/arcane_jaspr.dart';

class MyApp extends StatelessComponent {
  @override
  Component build(BuildContext context) {
    return ArcaneApp(
      theme: ArcaneTheme(
        themeMode: ThemeMode.dark,
        scheme: ContrastedColorScheme.blue(),
      ),
      child: Screen(
        header: Bar(titleText: 'My App'),
        child: Section(
          header: 'Welcome',
          children: [
            ArcaneCard(
              child: Component.text('Hello from Arcane Jaspr!'),
            ),
          ],
        ),
      ),
    );
  }
}

Styling

Using Styles.raw()

Arcane Jaspr provides a convenient Styles.raw() helper for inline CSS:

div(
  styles: Styles.raw({
    'display': 'flex',
    'gap': '16px',
    'padding': '24px',
    'background-color': 'var(--arcane-surface)',
    'border-radius': '8px',
  }),
  [
    Component.text('Content here'),
  ],
)

CSS Custom Properties

The theme system injects CSS custom properties that you can use throughout your app:

Property Description
--arcane-primary Primary brand color
--arcane-secondary Secondary color
--arcane-background Page background
--arcane-surface Card/container surface
--arcane-surface-variant Alternate surface color
--arcane-on-surface Text on surface
--arcane-on-surface-variant Secondary text
--arcane-outline Border color
--arcane-outline-variant Subtle border color
--arcane-error Error/destructive color
--arcane-success Success color
--arcane-warning Warning color

Components

Layout Components

Section

Groups content with an optional header:

Section(
  header: 'Settings',
  children: [
    // Content widgets
  ],
)

Gutter

Adds consistent spacing:

Column([
  widget1,
  Gutter.small(),   // 8px
  widget2,
  Gutter.medium(),  // 16px
  widget3,
  Gutter.large(),   // 24px
  widget4,
])

Flow

Responsive flow layout with wrapping:

Flow(
  gap: 12,
  children: [
    // Items that wrap when space is limited
  ],
)

ButtonPanel

Horizontal panel for action buttons:

ButtonPanel(
  children: [
    ArcaneButton.ghost(label: 'Cancel', onPressed: () {}),
    ArcaneButton.primary(label: 'Save', onPressed: () {}),
  ],
)

RadioCards

Selectable card options:

RadioCards<String>(
  value: selectedValue,
  onChanged: (value) => setState(() => selectedValue = value),
  items: [
    RadioCardItem(value: 'option1', title: 'Option 1', subtitle: 'Description'),
    RadioCardItem(value: 'option2', title: 'Option 2', subtitle: 'Description'),
  ],
)

Input Components

ArcaneButton

Various button styles:

ArcaneButton.primary(label: 'Primary', onPressed: () {})
ArcaneButton.secondary(label: 'Secondary', onPressed: () {})
ArcaneButton.outline(label: 'Outline', onPressed: () {})
ArcaneButton.ghost(label: 'Ghost', onPressed: () {})
ArcaneButton.destructive(label: 'Delete', onPressed: () {})

With icons:

ArcaneButton.primary(
  label: 'Save',
  leading: span([Component.text('\u2713')]),
  onPressed: () {},
)

ArcaneIconButton

Icon-only button:

ArcaneIconButton(
  icon: span([Component.text('\u2699')]),
  tooltip: 'Settings',
  onPressed: () {},
)

View Components

Bar

Application header bar:

Bar(
  leading: [
    ArcaneIconButton(
      icon: span([Component.text('\u2630')]),
      tooltip: 'Menu',
      onPressed: () {},
    ),
  ],
  titleText: 'My Application',
  trailing: [
    ArcaneIconButton(
      icon: span([Component.text('\u2699')]),
      tooltip: 'Settings',
      onPressed: () {},
    ),
  ],
)

ArcaneCard

Card container:

ArcaneCard(
  padding: EdgeInsets.all(16),
  child: Component.text('Card content'),
)

Clickable card:

ArcaneCard(
  onTap: () => print('Card tapped'),
  child: Component.text('Click me'),
)

Glass

Glassmorphism effect container:

Glass(
  blur: 10,
  opacity: 0.8,
  child: div(
    styles: Styles.raw({'padding': '24px'}),
    [Component.text('Frosted glass content')],
  ),
)

Expander

Collapsible content section:

Expander(
  title: 'Click to expand',
  initiallyExpanded: false,
  child: div([
    Component.text('Hidden content revealed when expanded'),
  ]),
)

Vertical navigation panel:

Sidebar(
  header: div([Component.text('My App')]),
  children: [
    SidebarItem(
      icon: span([Component.text('\u2302')]),
      label: 'Home',
      selected: currentIndex == 0,
      onTap: () => setState(() => currentIndex = 0),
    ),
    SidebarItem(
      icon: span([Component.text('\u2605')]),
      label: 'Favorites',
      selected: currentIndex == 1,
      onTap: () => setState(() => currentIndex = 1),
    ),
  ],
)

BottomNavigationBar

Mobile-style bottom navigation:

BottomNavigationBar(
  selectedIndex: currentIndex,
  onChanged: (index) => setState(() => currentIndex = index),
  items: [
    BottomNavItem(icon: span([Component.text('\u2302')]), label: 'Home'),
    BottomNavItem(icon: span([Component.text('\u{1F50D}')]), label: 'Search'),
    BottomNavItem(icon: span([Component.text('\u2665')]), label: 'Favorites'),
  ],
)

ArcaneTabs

Tabbed content:

ArcaneTabs(
  tabs: [
    ArcaneTabItem(
      label: 'Overview',
      content: div([Component.text('Overview content')]),
    ),
    ArcaneTabItem(
      label: 'Details',
      content: div([Component.text('Details content')]),
    ),
  ],
)

Dialog Components

ArcaneDialog

Modal dialog:

ArcaneDialog(
  title: 'Dialog Title',
  onClose: () => setState(() => showDialog = false),
  child: div([
    Component.text('Dialog content goes here'),
  ]),
  actions: [
    ArcaneButton.outline(label: 'Cancel', onPressed: () {}),
    ArcaneButton.primary(label: 'Confirm', onPressed: () {}),
  ],
)

ConfirmDialog

Pre-styled confirmation dialog:

ConfirmDialog(
  title: 'Delete Item?',
  message: 'This action cannot be undone.',
  confirmText: 'Delete',
  cancelText: 'Cancel',
  destructive: true,
  onConfirm: () => handleDelete(),
  onCancel: () => closeDialog(),
)

Toast

Toast notification:

Toast(
  message: 'Operation successful!',
  variant: ToastVariant.success,
  onClose: () => setState(() => showToast = false),
)

Toast variants: success, error, warning, info

Table Components

StaticTable

Simple table display:

StaticTable(
  headers: ['Name', 'Email', 'Role'],
  rows: [
    [Component.text('Alice'), Component.text('alice@example.com'), Component.text('Admin')],
    [Component.text('Bob'), Component.text('bob@example.com'), Component.text('User')],
  ],
)

DataTable

Interactive data table:

DataTable(
  headers: ['Name', 'Email', 'Role'],
  data: users,
  columns: [
    DataColumn(key: 'name'),
    DataColumn(key: 'email'),
    DataColumn(key: 'role'),
  ],
  onRowTap: (row) => print('Tapped: ${row['name']}'),
)

Theming

Basic Theme Setup

ArcaneApp(
  theme: ArcaneTheme(
    themeMode: ThemeMode.dark,
    scheme: ContrastedColorScheme.blue(),
  ),
  child: // Your app
)

Custom Color Scheme

ArcaneTheme(
  themeMode: ThemeMode.dark,
  scheme: ContrastedColorScheme(
    light: ColorScheme.light(
      primary: Color(0xFF6366F1),
      secondary: Color(0xFF8B5CF6),
      surface: Color(0xFFFFFFFF),
      background: Color(0xFFF8FAFC),
    ),
    dark: ColorScheme.dark(
      primary: Color(0xFF818CF8),
      secondary: Color(0xFFA78BFA),
      surface: Color(0xFF1E293B),
      background: Color(0xFF0F172A),
    ),
  ),
)

Built-in Color Schemes

ContrastedColorScheme.blue()
ContrastedColorScheme.green()
ContrastedColorScheme.purple()
ContrastedColorScheme.orange()
ContrastedColorScheme.red()

Theme Configuration Options

ArcaneTheme(
  themeMode: ThemeMode.dark,
  scheme: ContrastedColorScheme.blue(),
  radius: 0.5,           // Border radius scaling (0.0 - 1.0)
  surfaceOpacity: 0.8,   // Surface transparency
)

Demo Application

A complete demo application is included in the arcane_jaspr_demo package showing all components in action.

Documentation

License

MIT License - See LICENSE file for details.

Libraries

arcane_jaspr
Arcane Jaspr - A Jaspr port of the Arcane UI component library Supabase-inspired design with switchable accent colors
component/collection/collection
component/dialog/confirm
component/dialog/dialog
component/dialog/text
component/dialog/toast
component/feedback/alert_banner
component/feedback/loader
component/feedback/tooltip
component/form/field
component/form/field_wrapper
component/form/newsletter_form
component/form/provider
component/input/button
component/input/checkbox
component/input/cycle_button
component/input/fab
component/input/icon_button
component/input/selector
component/input/slider
component/input/text_input
component/input/theme_toggle
component/input/toggle_switch
component/interactive/accordion
component/interactive/back_to_top
component/layout/button_panel
component/layout/carpet
component/layout/cta_banner
component/layout/flow
component/layout/gutter
component/layout/hero_section
component/layout/radio_cards
component/layout/section
component/layout/tabs
component/navigation/bottom_navigation_bar
component/navigation/mobile_menu
component/screen/fill_screen
component/screen/screen
component/support/app
component/typography/headline
component/view/animated_counter
component/view/avatar
component/view/badge
component/view/bar
component/view/card
component/view/card_section
component/view/center_body
component/view/chip
component/view/code_snippet
component/view/data_table
component/view/divider
component/view/expander
component/view/feature_card
component/view/game_tile
component/view/glass
component/view/gradient_text
component/view/integration_card
component/view/pricing_card
component/view/progress_bar
component/view/rating_stars
component/view/skeleton
component/view/social_icons
component/view/stat_card
component/view/static_table
component/view/status_indicator
component/view/stepper
component/view/testimonial_card
component/view/tile
component/view/timeline
util/appearance/color_scheme
util/appearance/colors
util/appearance/theme
util/arcane
util/tokens/common_styles
Composable, spreadable style maps for common patterns Use with spread operator: Styles(raw: {...ArcaneCommonStyles.flexRow, 'gap': '16px'})
util/tokens/index
Barrel export for all Arcane design tokens
util/tokens/style_presets
Pre-built style presets that encapsulate all CSS for semantic meanings Usage: ArcaneButton(style: ButtonStyle.warning)
util/tokens/styles/alert_style
util/tokens/styles/badge_style
util/tokens/styles/button_style
util/tokens/styles/card_style
util/tokens/styles/chip_style
util/tokens/styles/control_styles
util/tokens/styles/fab_style
util/tokens/styles/icon_button_style
util/tokens/styles/input_style
util/tokens/styles/misc_styles
util/tokens/styles/progress_style
util/tokens/tokens
util/tools/styles