SfSkills Domains Docs GitHub

Home / lwc / lwc-in-flow-screens

lwc-in-flow-screens

Use when building, reviewing, or troubleshooting a custom Lightning Web Component that runs inside a Flow screen element, covering @api props exposed to Flow, FlowAttributeChangeEvent for output, validate() for user input validation, and flow navigation events. Triggers: 'lwc in flow screen', 'FlowAttributeChangeEvent', 'flow screen component not updating', 'flow validate method', 'flow navigation from lwc'. NOT for custom property editors (use custom-property-editor-for-flow), NOT for embedding a flow inside an LWC (use flow/screen-flows), NOT for auto-launched flows.

Open the skill folder on GitHub


Use this skill when a custom LWC component needs to participate in a Flow screen — receiving input from Flow variables, sending output back to Flow variables, validating user input before navigation, or controlling navigation programmatically. It covers the complete LWC-to-Flow contract: @api properties, FlowAttributeChangeEvent, the validate() method, and FlowNavigationXxxEvent events. This skill does not cover custom property editors, auto-launched flows, or embedding a flow inside an LWC.


Before Starting


Core Concepts

Mode 1 — Building a New LWC for a Flow Screen

The component must declare lightning__FlowScreen as a target in its .js-meta.xml file. Properties meant to receive Flow variable values are decorated with @api. Properties meant to send values back to Flow are also @api but are updated via FlowAttributeChangeEvent rather than direct mutation.

<!-- lwc-screen-comp.js-meta.xml -->
<targets>
  <target>lightning__FlowScreen</target>
</targets>
<targetConfigs>
  <targetConfig targets="lightning__FlowScreen">
    <property name="inputValue" type="String" role="inputOnly" />
    <property name="outputValue" type="String" role="outputOnly" />
  </targetConfig>
</targetConfigs>

In JavaScript, never mutate @api properties directly. Fire FlowAttributeChangeEvent to notify the runtime that an output property has a new value. The flow runtime applies the change; the component does not write to its own @api prop.

import { LightningElement, api } from 'lwc';
import { FlowAttributeChangeEvent } from 'lightning/flowSupport';

export default class MyFlowComp extends LightningElement {
  @api inputValue;
  @api outputValue;

  handleChange(event) {
    const newVal = event.detail.value;
    this.dispatchEvent(new FlowAttributeChangeEvent('outputValue', newVal));
  }
}

Mode 2 — Reviewing / Auditing an Existing Flow Screen Component

When reviewing an existing component, check these four contracts:

  1. Target declared — lightning__FlowScreen is in .js-meta.xml.
  2. Output path — output values are communicated only via FlowAttributeChangeEvent, not by direct @api assignment.
  3. Validation contract — if the component has internal validation, a validate() method exists and returns { isValid, errorMessage }.
  4. Navigation guard — if the component fires FlowNavigationNextEvent or FlowNavigationBackEvent, it first checks that availableActions includes NEXT or BACK respectively.

Mode 3 — Troubleshooting Data-Flow Issues

The most common data-flow symptoms and their root causes:

SymptomRoot cause
Output variable in Flow is always blank after the screenComponent is setting this.outputValue = x instead of firing FlowAttributeChangeEvent
Component appears correct but re-renders with stale value on Back navigationDerived output not re-fired in connectedCallback — fire FlowAttributeChangeEvent for derived attrs in both connectedCallback and the setter that triggers the change
validate() is never calledMethod is not named exactly validate (case-sensitive) or is not exported from the class
Navigation event fires but nothing happensavailableActions does not include the action; component fires the event regardless
Component not reactive when Flow passes a new inputComponent is reading @api in connectedCallback only; for setter-based reactivity, use the set accessor

FlowAttributeChangeEvent Datatype Constraints

The value parameter passed to FlowAttributeChangeEvent must match the Flow datatype of the corresponding @api property. Supported types are: String, Number, Boolean, and JSON (for record or SObject types). Passing a complex object where Flow expects a String causes silent failures. (Salesforce Developers: Set Up Your Screen Flow Components for Reactivity)

Components that drive navigation import the event classes from lightning/flowSupport and check availableActions before firing them. Available navigation events are:

If the component fires a navigation event that is not in availableActions, the event is ignored silently. (Salesforce Developers: Configure a Component for Flow Screens)


Common Patterns

Bidirectional Property With Reactive Output

When to use: The component receives a value from Flow (input) and must send a modified or user-entered value back (output) — the most common pattern for any form component.

How it works:

  1. Declare both @api inputValue and @api outputValue in JS.
  2. In the template, bind to a local reactive property (not directly to @api).
  3. On user change, fire FlowAttributeChangeEvent('outputValue', newVal).
  4. If the output is derived from inputValue, also fire FlowAttributeChangeEvent in connectedCallback and in the set inputValue() setter so Flow always sees the current value even when navigating back.
import { LightningElement, api, track } from 'lwc';
import { FlowAttributeChangeEvent } from 'lightning/flowSupport';

export default class BidirectionalComp extends LightningElement {
  @track _internalValue = '';

  @api
  get inputValue() {
    return this._internalValue;
  }
  set inputValue(val) {
    this._internalValue = val;
    // Re-fire derived output so Flow stays in sync on back-navigation
    this.dispatchEvent(new FlowAttributeChangeEvent('outputValue', this._computeOutput(val)));
  }

  @api outputValue;

  connectedCallback() {
    // Ensure output is initialized when component first mounts
    this.dispatchEvent(
      new FlowAttributeChangeEvent('outputValue', this._computeOutput(this._internalValue))
    );
  }

  handleChange(event) {
    this._internalValue = event.detail.value;
    this.dispatchEvent(new FlowAttributeChangeEvent('outputValue', this._internalValue));
  }

  _computeOutput(val) {
    return val ? val.trim() : '';
  }
}

Why not the alternative: Assigning this.outputValue = x bypasses the Flow runtime's change tracking and the value is never stored in the Flow variable.

Custom Validation Before Navigation

When to use: The component has business rules that must be satisfied before the user can proceed — for example, a date-range picker where the end date must be after the start date.

How it works: Implement a public validate() method that returns { isValid: Boolean, errorMessage: String }. The Flow runtime calls this method when the user attempts to navigate forward; if isValid is false, Flow blocks navigation and displays the errorMessage.

@api validate() {
  const isValid = this.startDate < this.endDate;
  return {
    isValid,
    errorMessage: isValid ? '' : 'End date must be after start date.'
  };
}

(Salesforce Developers: Validate Flow User Input)

Why not the alternative: Putting validation only inside a button click handler does not integrate with Flow's native validation cycle — the user can still navigate away by pressing the standard Next button.

Programmatic Navigation From the Component

When to use: The component should trigger navigation itself — for example, a custom "Skip this step" link or an action that completes after an async operation.

How it works:

import { LightningElement, api } from 'lwc';
import { FlowNavigationNextEvent, FlowNavigationBackEvent } from 'lightning/flowSupport';

export default class NavComp extends LightningElement {
  @api availableActions = [];

  handleNext() {
    if (this.availableActions.includes('NEXT')) {
      this.dispatchEvent(new FlowNavigationNextEvent());
    }
  }

  handleBack() {
    if (this.availableActions.includes('BACK')) {
      this.dispatchEvent(new FlowNavigationBackEvent());
    }
  }
}

Why not the alternative: Firing navigation events without checking availableActions creates silent failures that are hard to diagnose — the event fires but nothing happens.


Decision Guidance

SituationRecommended ApproachReason
Component needs to send a value back to a Flow variableFire FlowAttributeChangeEvent from an event handlerDirect @api mutation is not observed by the Flow runtime
Component has complex internal validationImplement validate() returning { isValid, errorMessage }Integrates with Flow's native navigation guard
Component should control navigation (e.g. auto-advance)Fire FlowNavigationNextEvent after checking availableActionsPrevents silent failures when the action is unavailable
Derived output depends on an input that Flow can changeFire FlowAttributeChangeEvent in both connectedCallback and the set accessorKeeps output in sync on both initial load and back-navigation
Component needs to configure properties visible in Flow BuilderDeclare <property> entries with role in .js-meta.xmlExposes the prop as an assignable input/output in Flow Builder
Auto-launched flow behavior is neededUse a different flow type — do not use a screen componentScreen components only execute within screen flows

Step-by-step instructions for an AI agent or practitioner activating this skill:

  1. Gather context — confirm the org edition, relevant objects, and current configuration state
  2. Review official sources — check the references in this skill's well-architected.md before making changes
  3. Implement or advise — apply the patterns from Core Concepts and Common Patterns sections above
  4. Validate — run the skill's checker script and verify against the Review Checklist below
  5. Document — record any deviations from standard patterns and update the template if needed

Review Checklist


Salesforce-Specific Gotchas

  1. Direct @api mutation is silently ignored by the Flow runtime — Setting this.outputProp = value inside the component looks correct in JavaScript but the Flow runtime does not observe @api writes from within the owning component. The Flow variable stays blank. Always fire FlowAttributeChangeEvent.
  2. Back navigation loses derived output if not re-fired in connectedCallback — When the user navigates back to a screen, the component remounts and connectedCallback runs again. If a derived output is only emitted in a change handler, the Flow variable reverts to its pre-component value. Fire FlowAttributeChangeEvent for all derived outputs in connectedCallback.
  3. validate() must be exactly that name — The Flow runtime looks for a method named validate on the component instance. A method named validateInput or runValidation is ignored. Navigation is allowed regardless of internal state.

Output Artifacts

ArtifactDescription
Reviewed or scaffolded LWCComponent with correct target declaration, @api properties, and event-based output
FlowAttributeChangeEvent auditList of output properties and whether they are correctly wired
validate() implementationMethod returning { isValid, errorMessage } integrated with Flow's navigation guard
Navigation-action guardavailableActions check before any FlowNavigationXxxEvent dispatch
Data-flow issue reportIdentified root causes with corrective steps for each symptom

Package files