RemixRemix

Build a settings screen

Use Remix CLI recipes to build, customize, and test a Flutter settings screen

Build Launchpad, a desktop-browser settings screen with a form, save state, dialog, and sidebar. You write the application; the CLI installs editable component recipes and their theme.

Launchpad with Vanilla, October 31 Flutter test-renderer capture

The finished screenshot includes the medium Button height edit below. It is an application example, not a screen the CLI generates for you.

This walkthrough includes the complete application and test source below. The sample download contains both projects, generated adapters, and four behavior tests per preset.

Before you start

Use Flutter 3.44.0, its bundled Dart 3.12.0, Git, and a desktop browser. The samples use local state, with no backend or responsive mobile layout. Both hosts explicitly use Geist from remix_ui_fonts, so app text and owned recipes share a reproducible font.

This replay pins both the CLI checkout and the remote registry to 2556203413520874c4e6d7682e8e1737f4b9f360 (Remix 1.0.0-beta.13, CLI 1.0.0-beta.0). The compact preset is named vanilla; the sample directory keeps the original default_demo name.

The September 7 browser/editor images remain labeled historical. The October 31 overview captures use the real Flutter test renderer with the pinned SDK; they are not browser screenshots. Browser automation was unavailable during this replay. Both applications also pass release web builds.

Prepare the project and CLI

In the directory where you keep applications:

flutter create --empty --platforms=web remix_default_demo
cd remix_default_demo

In a second terminal, get the reviewed Remix checkout:

git clone https://github.com/btwld/remix.git remix-review
git -C remix-review checkout 2556203413520874c4e6d7682e8e1737f4b9f360
git -C remix-review rev-parse --show-toplevel

Use the printed absolute path in place of /path/to/remix below. Back in remix_default_demo, create pubspec_overrides.yaml:

dependency_overrides:
  remix:
    path: /path/to/remix/packages/remix
  remix_ui_fonts:
    path: /path/to/remix/packages/remix_ui_fonts

Then install the checkout CLI as a project-local development dependency:

dart pub add "dev:remix_cli@{path: /path/to/remix/packages/remix_cli}"
dart run remix_cli:remix --version

The version should be 1.0.0-beta.0. Keep running CLI commands from the sample's package root, beside pubspec.yaml.

Initialize and install Button

dart run remix_cli:remix init --prefix Acme --preset vanilla
dart run remix_cli:remix registry update @remix --ref 2556203413520874c4e6d7682e8e1737f4b9f360

Acme controls local names such as AcmeButton and acmeButtonStyle. Initialization resolves the stable registry; the next command pins the replay revision explicitly. It writes remix.yaml and a managed barrel at lib/ui/ui.dart. It does not install a component yet.

Preview the first install:

dart run remix_cli:remix add button --dry-run

The plan should install theme before button. No source is written by --dry-run. Install when the plan matches:

dart run remix_cli:remix add button

Inspect lib/ui/components/button.dart, the recipe you own, and button.g.dart, the adapter produced by the generator. Edit the recipe, not the generated file. The CLI also adds the required dependencies and exports.

Render the first button

Replace lib/main.dart with this complete example:

import 'package:flutter/widgets.dart';

import 'ui/ui.dart';

void main() => runApp(const AcmeApp());

class AcmeApp extends StatelessWidget {
  const AcmeApp({super.key});

  @override
  Widget build(BuildContext context) {
    return WidgetsApp(
      color: const Color(0xFF000000),
      builder: (_, _) => Overlay(
        initialEntries: [
          OverlayEntry(
            builder: (_) => const AcmeTheme(
              theme: AcmeThemeData.light(),
              child: HomePage(),
            ),
          ),
        ],
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    final theme = AcmeTheme.of(context);
    return ColoredBox(
      color: theme.background,
      child: Center(
        child: AcmeButton.primary(
          label: 'Continue',
          onPressed: () {},
        ),
      ),
    );
  }
}
flutter run -d chrome

Historical September 7 capture: the default Continue button on a white surface

You should see Continue centered in the app. Its callback is deliberately empty at this stage. Keep this terminal open; use another terminal in the same sample directory for the remaining CLI commands.

Build the settings screen

Install the remaining recipes, one item per command:

dart run remix_cli:remix add checkbox
dart run remix_cli:remix add textfield
dart run remix_cli:remix add dialog
dart run remix_cli:remix add card
dart run remix_cli:remix add sidebar
dart run remix_cli:remix add sidebar_layout
flutter pub add "remix_ui_fonts:^0.1.0"

The existing theme is preserved. Sidebar also installs its toggle and tooltip dependencies. Sidebar Layout is a plain shell layout — no Spec, no generated adapter — that pairs an installed sidebar with a header and body, switching to a start-edge sheet below its compact breakpoint. Each command updates the barrel and generates the needed adapters.

Replace your application's lib/main.dart with the complete Vanilla source below. The same file is default_demo/lib/main.dart in the reviewed samples. Keep your CLI-installed lib/ui files; the next step changes one of them.

The complete app owns the form values, save counter, loading flag, dialog result, and sidebar selection. It uses WidgetsApp with a Navigator as the application host. Keep its host builder and scope placement together: the text field needs an overlay, and the dialog needs the invoking context's navigator and text defaults.

Customize your recipe

Open lib/ui/components/button.dart. In _metricsFor, change the medium minHeight from AcmeTokens.controlMd (36 pixels) to 44.0. Reload the app. All medium default buttons should use the taller recipe, while the cyan preview button keeps its instance-specific colors and rounded shape.

Historical September 7 editor capture: literal 36.0 changed to 44.0; current recipes use AcmeTokens.controlMd

This changes a recipe value, not the generated widget signature. If you change recipe parameters, enums, or annotations, regenerate the adapter as described in the customization reference.

Check behavior and preserve edits

  1. Reload to reset local state. Enter Launchpad Studio as the workspace name.
  2. Clear Send a weekly summary, then press Save changes twice while loading.
  3. Confirm Save count: 1 and Summary: off when the save completes.
  4. Open and confirm the invitation dialog. Check that its result reaches the screen.
  5. Change the sidebar selection and test the preview button's callback.

Historical September 7 capture: saved form values with one completed save and summary off

Now compare your edited Button with its pinned registry recipe:

dart run remix_cli:remix add button --diff

The diff's current side contains your 44.0 edit; proposed contains the registry token AcmeTokens.controlMd. The command does not replace your source. Repeat ordinary add:

dart run remix_cli:remix add button

Confirm the medium height remains 44.0. --overwrite is an explicit replacement operation; do not use it to inspect an update. See source-preservation details before trying it.

Try Fortal separately

Do not switch the Vanilla project's preset. From its directory, create a second application:

cd ..
flutter create --empty --platforms=web remix_fortal_demo
cd remix_fortal_demo

Repeat the checkout override and CLI installation from the first step in this new project. Then initialize Fortal and install its recipes:

dart run remix_cli:remix init --prefix Acme --preset fortal
dart run remix_cli:remix registry update @remix --ref 2556203413520874c4e6d7682e8e1737f4b9f360
dart run remix_cli:remix add button
dart run remix_cli:remix add checkbox
dart run remix_cli:remix add textfield
dart run remix_cli:remix add dialog
dart run remix_cli:remix add card
dart run remix_cli:remix add sidebar
dart run remix_cli:remix add sidebar_layout
flutter pub add "remix_ui_fonts:^0.1.0"

Replace this app's lib/main.dart with the complete Fortal source below, also available as fortal_demo/lib/main.dart in the download.

The Fortal example uses AcmeTheme with the Mar accent and AcmeButton.solid, rather than AcmeButton.primary. Keep its complete host configuration. Do not apply the Vanilla preset's Button metrics edit to Fortal.

Launchpad with Fortal Mar in dark mode, October 31 Flutter test-renderer capture

Fortal supplies a different theme and recipe vocabulary, not a second runtime for your form. Repeat the same behavior checks. Neither preset adds a remix_fortal package dependency to the consumer application.

Run the tests

Copy test/workflow_test.dart from the matching downloaded project into each sample. Keep the project names used above; the tests import those names.

Replace analysis_options.yaml with the reviewed configuration:

include: package:flutter_lints/flutter.yaml

analyzer:
  exclude:
    - lib/ui/**/*.g.dart

This excludes generated adapters from the pinned generator's lint findings, not your authored recipes. Run from each sample directory:

flutter analyze
flutter test
flutter build web --release

Each sample has four tests covering form/save behavior, disabled controls, callbacks, dialog results and text decoration, and sidebar selection. Fix failures before treating a screenshot as evidence that the sample works.

Troubleshooting and evidence

  • Pub cannot resolve remix: the samples depend on ^1.0.0-beta.13 and resolve it through the absolute checkout path in pubspec_overrides.yaml; check that path.
  • Missing generated class: inspect the add command's generation error and the recipe's part declaration.
  • Missing overlay or incorrect dialog text: restore the complete sample's application host and scope placement.
  • No primary constructor: use the Vanilla sample, selected with --preset vanilla, or the solid constructor with fortal.

See the Open Code reference for configuration and command details.

Historical JPGs were captured from Flutter release web builds and an editor during the September 7 review, at checkout bfae6507676fadea7632e2f7f66924935c04ca2a. Current PNG overviews were rendered on October 31 from the downloaded source with Flutter 3.44.0 widget tests. They show desktop states, not certification of all components or platforms. Recorded evidence tracks each capture method, hashes, and source checkout. Assets and evidence remain alongside this documentation. Source panels above are expanded from the same archive during the documentation build, not maintained as separate copies.

View page source on GitHub