Build beautiful apps with Flutter

Check out the live sample app Papilio Note in the browser. All source code is available for the sample app here. Or, check out this package’s simple example app here. Notice that both samples fully integrate with browser navigation.

Papilio Note

Declaritive Framework for Flutter

Compose your app with ease and leave the plumbing up to the framework

Separation of Concerns

Separate your app’s logic from its presentation

BloC Approach to State Management

Send events to the business logic component and let the framework handle UI changes from the stream

Compose Your Dependencies

Access you dependencies with dependency injection when you need them in the app. papilio uses the ioc_container package

Declarative Approach to Navigation

Specify page names and StatelessWidgets to seamlessly transition between pages. Respond to navigation from BloC handlers instead of UI callbacks

You can compose your app like this. It’s nice.

void main() {
  const incrementName = '/increment';
  const incrementKey = ValueKey(incrementName);
  const decrementName = '/decrement';
  const decrementKey = ValueKey(decrementName);

  final builder = IocContainerBuilder();

    (container) => PapilioRoutingConfiguration<PageRoute>(
        buildRoutes: (delegateBuilder) => delegateBuilder
              container: container,
              name: incrementName,
              initialState: (arguments) => const PageState(0, 0),
              pageBody: (context) => const MyHomePage<Increment>(
                  title: "Papilio Sample - Increment"),
              buildBloc: (blocBuilder, container) => blocBuilder
                ..addSyncHandler<Increment>((state, event) =>
                    state.copyWith(counter: state.counter + 1))
                ..addSyncHandler<NavigateToIndex>((state, event) {
                  if (event.index == 0) {
                    return state;
                  container.navigate<PageState, PageRoute>(decrementKey);
                  return state;
              container: container,
              name: decrementName,
              initialState: (arguments) => const PageState(10, 1),
              pageBody: (context) => const MyHomePage<Decrement>(
                  title: "Papilio Sample - Decrement"),
              buildBloc: (blocBuilder, container) => blocBuilder
                ..addSyncHandler<Decrement>((state, event) =>
                    state.copyWith(counter: state.counter - 1))
                ..addSyncHandler<NavigateToIndex>((state, event) {
                  if (event.index == 1) {
                    return state;
                  container.navigate<PageState, PageRoute>(incrementKey);
                  return state;
        currentRouteConfiguration: (page) => == incrementName
            ? const PageRoute(Page.increment)
            : const PageRoute(Page.decrement),
        parseRouteInformation: (routeInformation) async =>
            routeInformation.location == incrementName
                ? const PageRoute(Page.increment)
                : const PageRoute(Page.decrement),
        restoreRouteInformation: (pageRoute) => RouteInformation(
            location: == Page.increment
                ? incrementName
                : decrementName),
        onSetNewRoutePath: (delegate, route) async =>
   == Page.increment
                ? delegate.navigate<PageState>(incrementKey)
                : delegate.navigate<PageState>(decrementKey),
        onInit: (delegate, container) =>

  final container = builder.toContainer();

Widget tests in the Papilio Note sample cover this package thoroughly, but this repo will soon have unit tests. View the widget tests here.


View Github