Skip to content
Skip to content
Goodspeed

BUILT INTO EVERY GOODSPEED APP

Dark Mode

Dark and light mode ship in every Goodspeed app via a config-driven ThemeContext. System preference is respected by default; users can override with a manual toggle. All design tokens resolve correctly in both schemes.

  • Tier: Core
  • Status: Config-toggled
  • Config: features.darkMode

WHY IT MATTERS

Most mobile app projects spend weeks plumbing the same infrastructure before writing a single line of product code. Dark Mode is one of those cross-cutting concerns that every app eventually needs but almost none get right the first time. Permissions are handled incorrectly, tokens expire silently, or the feature breaks after an OS update nobody tested against.

Goodspeed solves this by shipping dark mode as a production-grade, tested implementation inside every generated app. The code follows the patterns in the GAS template - the same 246-feature catalog that powers every app we build. Controlled by `features.darkMode` in gas.config.ts. You own the code from day one, can read every line, and can hire any React Native developer to extend it. The build pipeline verifies the feature compiles and routes resolve before the app lands in your repository, so you are not the one catching the integration error at 2 am before launch.

HOW IT IS WIRED

Real code from the GAS template

The excerpt below is lifted verbatim from context/ThemeContext.tsx in the gas-template repository. This is the code your generated app gets, not pseudocode, not a description of intent.

// context/ThemeContext.tsx — theme resolution
const LightColors = {
  primary:    configColors.primary,
  background: configColors.background,
  surface:    configColors.surface,
  text:       configColors.text,
  textSecondary: configColors.textSecondary,
  border:     configColors.border,
};

const DarkColors = {
  primary:    configColors.primary,
  background: configColors.backgroundDark,
  surface:    configColors.surfaceDark,
  text:       configColors.textDark,
  textSecondary: configColors.textSecondaryDark,
  border:     configColors.borderDark,
};

export function ThemeProvider({ children }: { children: ReactNode }) {
  const { resolved, preference, setTheme } = useTheme();
  const colors = resolved === 'dark' ? DarkColors : LightColors;
  return (
    <ThemeContext.Provider value={{ colors, resolved, preference, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

Source: goodspeed-apps/gas-template context/ThemeContext.tsx

HONEST LIMITS

When Dark Mode is the wrong choice

If your brand mandates a single fixed color palette (common in regulated finance or healthcare apps with strict accessibility audits), disable the toggle and hard-code one scheme via gasConfig to avoid diverging token paths.

Tier: Core · Config-toggled

  1. Evaluate your use case

    Check whether dark mode aligns with your target audience, platform constraints, and regulatory environment before enabling it.

  2. Audit the config

    The `features.darkMode` flag controls this feature. Set it to false in gas.config.ts to disable the feature entirely with no residual code paths.

  3. Seek alternatives

    If the built-in implementation does not fit, the generated codebase is standard React Native + Expo code. Any library in the Expo ecosystem can replace the default.

APPS USING THIS FEATURE

Apps built with Dark Mode

These apps were generated by Goodspeed and use dark mode as a core part of their experience. Each link goes to the full app marketing page.

CAPABILITIES

Dark Mode capability breakdown

Concrete dimensions of what the built-in dark mode implementation covers. These reflect the actual template code, not a marketing summary.

ItemDescriptionStrength
Default schemeSystem preference is followed by default. Users can override to force light or dark via a toggle.System + manual
Token resolutionLightColors and DarkColors objects derive all values from gasConfig.design.colors at module load time.Config-driven
Dynamic typeFont scale from iOS Dynamic Type is observed via useDynamicType and applied to text size tokens.iOS Dynamic Type
Reduced motionuseReducedMotion disables transitions and animations when the accessibility setting is active.Accessibility-aware

GET IT BUILT INTO YOUR APP

Score your idea and get dark mode wired in from day one