> ## Documentation Index
> Fetch the complete documentation index at: https://developer.watson-orchestrate.ibm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# User activity node

Use a user activity node to define interactive steps in your agentic workflow where users provide or receive information in one of two ways:

* In a multi-turn conversation, where the user provides or receives one piece of data at a time
* Through a form, which prompts the user for several pieces of data in a single conversational turn

<Note>
  **Note:**

  User activity nodes support multi-language configurations. Define target languages in your agentic workflow code and manage translations through CSV export and import. For complete details, see [Multi-language support](./multi_language_overview).
</Note>

To add a user activity node to your agentic workflow, start by creating a `userflow()` object.

## Multi-turn conversations user activity

To collect or deliver one piece of data at a time, call `field()` on the `userflow()` object. This method accepts the following input parameters:

<ParamField path="name" type="string" required>
  Unique identifier for the node.
</ParamField>

<ParamField path="kind" type="UserFieldKind" required>
  Type of user activity. Supported types: Text, Date, DateTime, Time, Number, File, Boolean, Object, Choice.
</ParamField>

<ParamField path="display_name" type="string">
  Display name for the node.
</ParamField>

<ParamField path="description" type="string">
  Description of the node.
</ParamField>

<ParamField path="direction" type="string" required>
  Indicates whether the node is for input or output.
</ParamField>

<ParamField path="default" type="any">
  Default value for the node.
</ParamField>

<ParamField path="option" type="UserFieldOption">
  List of predefined options with their labels and values.
</ParamField>

<ParamField path="is_list" type="bool">
  Indicates whether the node accepts multiple values.
</ParamField>

<ParamField path="min" type="any">
  Minimum value or constraint.
</ParamField>

<ParamField path="max" type="any">
  Maximum value or constraint.
</ParamField>

<ParamField path="input_map" type="DataMap">
  Define input mappings using a structured collection of Assignment objects.
</ParamField>

<ParamField path="custom" type="dictionary">
  Dictionary for additional metadata or configuration.
</ParamField>

Here is an example that shows how to use `field()`:

```py Python [expandable] theme={null}
from typing import List
from pydantic import BaseModel, Field
from ibm_watsonx_orchestrate.flow_builder.flows import (
    Flow, flow, UserNode, START, END
)
from ibm_watsonx_orchestrate.flow_builder.types import Assignment, UserFieldKind
from ibm_watsonx_orchestrate.flow_builder.data_map import DataMap

class Name(BaseModel):
    """
    This class represents a person's name.

    Attributes:
        name (str): The person's first name.
    """
    first_name: str = Field(default="John Doe", description="First name")

@flow(
    name ="user_flow_example",
    display_name="user_flow_example",
    description="Example user flow.",
    input_schema=Name,
)
def build_user_flow(aflow: Flow = None) -> Flow:
    # user_flow which is a subflow to be added to the aflow
    user_flow = aflow.userflow()

    # add file upload
    user_node1 = user_flow.field(direction="input",name="upload", display_name="File upload 1",  kind=UserFieldKind.File)

    # add file download
    data_map = DataMap()
    data_map.add(Assignment(target_variable="self.input.value",value_expression="flow[\"userflow_1\"][\"File upload 1\"].output.value"))
    user_node2 = user_flow.field(direction="output",name="download", display_name="Download file",  kind=UserFieldKind.File, input_map=data_map)

    # add a Display user text field
    user_node3 = user_flow.field(direction="output",name="display_first_name", display_name="Display first name", kind=UserFieldKind.Text, text="Display of first name is {flow.input.first_name}")

    # add a text input field
    user_node4 = user_flow.field(direction="input",name="last_name", display_name="Last name",  kind=UserFieldKind.Text)
    
    # add a Number input field
    user_node5 = user_flow.field(direction="input",name="age", display_name="Age",  kind=UserFieldKind.Number)

    # create a data map to build an array to be assigned to a user field of kind List
    data_map = DataMap()
    data_map.add(Assignment(target_variable="self.input.value",value_expression="[\"Alice\", \"Bob\", \"Charlie\", \"Diana\", \"Ethan\", \"Fiona\", \"George\"]"))
    user_node6 = user_flow.field(direction="output",name="Friends", display_name="List of friends", kind=UserFieldKind.List, input_map=data_map)

    # add a Choice input field
    data_map_choices = DataMap()
    data_map_choices.add(Assignment(target_variable="self.input.choices",value_expression='["dog", "cat", "bird", "fish"]'))
    user_node7 = user_flow.field(direction="input",name="pet_choice",display_name="Select Your Pet",kind=UserFieldKind.Choice,text="Choose your favorite pet:",input_map=data_map_choices)
    
    # A user flow edges
    user_flow.edge(START, user_node1)
    user_flow.edge(user_node1, user_node2)
    user_flow.edge(user_node2, user_node3)
    user_flow.edge(user_node3, user_node4)
    user_flow.edge(user_node4, user_node5)
    user_flow.edge(user_node5, user_node6)
    user_flow.edge(user_node6, END)
    
    # add the user flow to the flow sequence to create the flow edges
    aflow.sequence(START, user_flow, END)

    return aflow
```

## Forms user activity

To prompt for multiple pieces of data in a single turn, instantiate the `form()` object to create a form node. This method accepts the following input parameters:

<ParamField path="name" type="string" required>
  The internal name of the form.
</ParamField>

<ParamField path="display_name" type="string">
  The display name shown on the form.
</ParamField>

<ParamField path="instructions" type="string">
  Instructions text for the form.
</ParamField>

<ParamField path="submit_button_label" type="string">
  The label for the submit button. Defaults to `Submit` if not set.
</ParamField>

<ParamField path="cancel_button_label" type="string">
  The label for the cancel button. If set to None, hides the button.
</ParamField>

### Forms fields

After instantiating the form object, add fields to it. Each field type requires its own configuration. Supported field types include:

<AccordionGroup>
  <Accordion title="text_input_field">
    Creates a text input field. Configure it as a single-line input or a multi-line text area.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="required" type="bool">
      Whether the field is required. Defaults to `False`.
    </ParamField>

    <ParamField path="single_line" type="bool">
      Whether the field uses a single line. If `False`, creates a multi-line text area. Defaults to `True`.
    </ParamField>

    <ParamField path="placeholder_text" type="string">
      Placeholder text for the field.
    </ParamField>

    <ParamField path="help_text" type="string">
      Help text for the field.
    </ParamField>

    <ParamField path="default" type="any">
      Default value for the field, passed as DataMap.
    </ParamField>

    <ParamField path="regex" type="string">
      Regular expression pattern for input validation.
    </ParamField>

    <ParamField path="regex_error_message" type="string">
      Custom error message for failed regex validation.
      Defaults to: "Input does not match the required pattern".
    </ParamField>
  </Accordion>

  <Accordion title="boolean_input_field">
    Creates a boolean input field. Render it as a checkbox or radio buttons.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="single_checkbox" type="bool">
      Whether to display as a single checkbox. If `False`, displays as radio buttons. Defaults to `True`.
    </ParamField>

    <ParamField path="default" type="any">
      Default value for the field, passed as `input_map`.
    </ParamField>

    <ParamField path="true_label" type="string">
      Label for the true option. Defaults to `True`.
    </ParamField>

    <ParamField path="false_label" type="string">
      Label for the false option. Defaults to `False`.
    </ParamField>
  </Accordion>

  <Accordion title="date_range_input_field">
    Creates a date range input field with start and end date pickers.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="required" type="bool">
      Whether the field is required. Defaults to `False`.
    </ParamField>

    <ParamField path="start_date_label" type="string">
      Label for the start date field.
    </ParamField>

    <ParamField path="end_date_label" type="string">
      Label for the end date field.
    </ParamField>

    <ParamField path="default_start" type="any">
      Default value for the start date, passed as DataMap.
    </ParamField>

    <ParamField path="default_end" type="any">
      Default value for the end date, passed as DataMap.
    </ParamField>

    <ParamField path="min_date" type="any">
      DataMap that sets the minimum date constraint and maps to `self.input.min_date`.
    </ParamField>

    <ParamField path="max_date" type="any">
      DataMap that sets the maximum date constraint and maps to `self.input.max_date`.
    </ParamField>
  </Accordion>

  <Accordion title="date_input_field">
    Creates a date input field.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="required" type="bool">
      Whether the field is required. Defaults to `False`.
    </ParamField>

    <ParamField path="default" type="any">
      Default value for the field, passed as DataMap.
    </ParamField>

    <ParamField path="min_date" type="any">
      Minimum date value for the allowed range.
    </ParamField>

    <ParamField path="max_date" type="any">
      Maximum date value for the allowed range.
    </ParamField>

    <ParamField path="multiple_dates" type="bool">
      Whether the field supports selecting more than one date. Defaults to `False`.
    </ParamField>
  </Accordion>

  <Accordion title="datetime_input_field">
    Creates a datetime or time input field.

    <ParamField path="name" type="string" required>
      Internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="required" type="bool">
      Whether the field is required. Defaults to `False`.
    </ParamField>

    <ParamField path="default" type="any">
      Default value for the field, provided through a `DataMap`.
    </ParamField>

    <ParamField path="min_time" type="any">
      Minimum allowed datetime or time value.
    </ParamField>

    <ParamField path="max_time" type="any">
      Maximum allowed datetime or time value.
    </ParamField>

    <ParamField path="inputType" type="UserFieldKind">
      Type of field, either `DateTime` or `Time`. Defaults to `DateTime`.
    </ParamField>
  </Accordion>

  <Accordion title="datetime_range_input_field">
    Creates a datetime or time range input field with start and end pickers.

    <ParamField path="name" type="string" required>
      Internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="required" type="bool">
      Whether the field is required. Defaults to `False`.
    </ParamField>

    <ParamField path="start_date_label" type="string">
      Label for the start value.
    </ParamField>

    <ParamField path="end_date_label" type="string">
      Label for the end value.
    </ParamField>

    <ParamField path="default_start" type="any">
      Default start value, provided through a `DataMap`.
    </ParamField>

    <ParamField path="default_end" type="any">
      Default end value, provided through a `DataMap`.
    </ParamField>

    <ParamField path="min_time" type="any">
      Minimum allowed value for the range.
    </ParamField>

    <ParamField path="max_time" type="any">
      Maximum allowed value for the range.
    </ParamField>
  </Accordion>

  <Accordion title="number_input_field">
    Creates a number input field.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="required" type="bool">
      Whether the field is required. Defaults to `False`.
    </ParamField>

    <ParamField path="is_integer" type="bool">
      Whether the field accepts only integers. If `False`, accepts decimal numbers. Defaults to `True`.
    </ParamField>

    <ParamField path="help_text" type="string">
      Help text for the field.
    </ParamField>

    <ParamField path="default" type="any">
      Default value for the field, passed as DataMap.
    </ParamField>

    <ParamField path="minimum" type="any">
      Minimum allowed value, passed as DataMap.
    </ParamField>

    <ParamField path="maximum" type="any">
      Maximum allowed value, passed as DataMap.
    </ParamField>
  </Accordion>

  <Accordion title="file_upload_field">
    Creates a file upload field.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="instructions" type="string">
      Instructions for the file upload.
    </ParamField>

    <ParamField path="required" type="bool">
      Whether the field is required. Defaults to `False`.
    </ParamField>

    <ParamField path="allow_multiple_files" type="bool">
      Whether multiple files can be uploaded. Defaults to `False`.
    </ParamField>

    <ParamField path="file_max_size" type="int">
      Maximum file size in MB. Defaults to `10`.
    </ParamField>

    <ParamField path="supported_file_types" type="List[string]">
      List of supported file extensions, for example pdf and docx.
    </ParamField>

    <ParamField path="min_num_files" type="Any">
      Minimum number of files. Valid only `when allow_multiple_files=True`.
    </ParamField>

    <ParamField path="max_num_files" type="Any">
      Maximum number of files. Valid only `when allow_multiple_files=True`.
    </ParamField>
  </Accordion>

  <Accordion title="message_output_field">
    Creates a message output field to display static text.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="message" type="string">
      The message text to display.
    </ParamField>
  </Accordion>

  <Accordion title="field_output_field">
    Creates a field output to display dynamic values.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="value" type="any">
      The value to display, passed as DataMap.
    </ParamField>
  </Accordion>

  <Accordion title="list_output_field">
    Creates a list output field to display tabular data.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="choices" type="any">
      The list of items to display, passed in a DataMap.
    </ParamField>

    <ParamField path="columns" type="dict[string, str]">
      Mapping of source property names to table column labels. Only those columns appear if present.
    </ParamField>
  </Accordion>

  <Accordion title="list_input_field">
    Creates a list input field to display tabular data.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="isRowAddable" type="bool">
      Whether the user can add rows.
    </ParamField>

    <ParamField path="isRowDeletable" type="bool">
      Whether the user can delete rows.
    </ParamField>

    <ParamField path="default" type="any">
      The list of items to display, passed in a DataMap.
    </ParamField>

    <ParamField path="columns" type="dict[string, str]">
      Mapping of source property names to table column labels. Only those columns appear if present.
    </ParamField>
  </Accordion>

  <Accordion title="file_download_field">
    Creates a file download field.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="value" type="any">
      The file to download, passed as DataMap.
    </ParamField>
  </Accordion>

  <Accordion title="single_choice_input_field">
    Creates a single-choice input field. Display options as a dropdown or as radio buttons.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="required" type="bool">
      Whether the field is required. Defaults to `False`.
    </ParamField>

    <ParamField path="choices" type="any">
      The list of available choices, passed as DataMap.
    </ParamField>

    <ParamField path="show_as_dropdown" type="bool">
      Whether to display options as a dropdown. If `False`, display as radio buttons. Defaults to `True`.
    </ParamField>

    <ParamField path="dropdown_item_column" type="string">
      Column name used for display text in dropdown.
    </ParamField>

    <ParamField path="placeholder_text" type="string">
      Placeholder text for the dropdown.
    </ParamField>

    <ParamField path="default" type="any">
      Default selected value, passed as DataMap.
    </ParamField>

    <ParamField path="columns" type="dict[string, str]">
      Mapping of source property names to display labels for complex choice objects.
    </ParamField>
  </Accordion>

  <Accordion title="multi_choice_input_field">
    Creates a multi-choice input field. Display options as a multi-select dropdown or as checkboxes.

    **Parameters:**

    <ParamField path="name" type="string" required>
      The internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="required" type="bool">
      Whether the field is required. Defaults to `False`.
    </ParamField>

    <ParamField path="choices" type="any">
      The list of available choices, passed as DataMap.
    </ParamField>

    <ParamField path="show_as_dropdown" type="bool">
      Whether the field shows as a dropdown. If `False`, the field shows as checkboxes. Defaults to `True`.
    </ParamField>

    <ParamField path="dropdown_item_column" type="string">
      Column name for the display text in a dropdown.
    </ParamField>

    <ParamField path="placeholder_text" type="string">
      Placeholder text for the dropdown.
    </ParamField>

    <ParamField path="default" type="any">
      Default selected values, provided as a DataMap.
    </ParamField>

    <ParamField path="columns" type="dict[string, str]">
      Mapping of source property names to display labels for complex choice objects.
    </ParamField>

    <ParamField path="minItems" type="any">
      Minimum number of items the user must select.
    </ParamField>

    <ParamField path="maxItems" type="any">
      Maximum number of items the user can select.
    </ParamField>
  </Accordion>

  <Accordion title="user_input_field">
    Creates a user selection field in the form.

    **Parameters:**

    <ParamField path="name" type="string" required>
      Internal name of the field.
    </ParamField>

    <ParamField path="label" type="string">
      Display label for the field.
    </ParamField>

    <ParamField path="required" type="bool">
      Whether the field is required. Defaults to `False`.
    </ParamField>

    <ParamField path="multiple_users" type="bool">
      Whether the user can select more than one person. Defaults to `False`.
    </ParamField>

    <ParamField path="min_num_users" type="any">
      Minimum number of users to select. Applies only when `multiple_users=True`. Accepts an integer or a DataMap for dynamic configuration through expressions.
    </ParamField>

    <ParamField path="max_num_users" type="any">
      Maximum number of users to select. Applies only when `multiple_users=True`. Accepts an integer or a DataMap for dynamic configuration through expressions.
    </ParamField>
  </Accordion>
</AccordionGroup>

Here is an example that shows how to use `form()`:

```py Python [expandable] theme={null}
from typing import List
from pydantic import BaseModel, Field
from ibm_watsonx_orchestrate.flow_builder.flows import (
    Flow, flow, UserNode, START, END
)
from ibm_watsonx_orchestrate.flow_builder.types import Assignment, UserFieldKind
from ibm_watsonx_orchestrate.flow_builder.data_map import DataMap

class Name(BaseModel):
    """
    This datatype represents a person's name.

    Attributes:
        name (str): The person's first name.
    """
    first_name: str = Field(default="John", description="First name")
    last_name: str = Field(default="Doe", description="Last name")

class Book(BaseModel):
    """
    This datatype represents a book.

    Attributes:
        title (str): The book's title.
        author (str): The book's author.
    """
    title: str = Field(default="Shaken", description="Book title")
    author: str = Field(default="John Grisham", description="Author")

class StringListNames(BaseModel):
    listOfNames: List[Name] = Field(
        default=[{"John", "Doe"}, {"Jane", "Doe"}, {"Jean", "Doe"}],
        description="A list of Name objects with first and last names."
    )

class MyDate(BaseModel):
    """
    This datatype represents date information.

    Attributes:
        dateStart (str): The start date.
        dateEnd (str): The end date.
        dateEvent (str): The event date.
    """
    dateStart: str = Field(default="2023-01-01", description="Start date")
    dateEnd: str = Field(default="2023-12-31", description="End date")
    dateEvent: str = Field(default="2023-06-15", description="Event date")

class FlowInput(BaseModel):
    salutations: List[str] = Field(
        default=["Mr", "Mrs"],
        description="A list of string salutations."
    )
    listOfLanguages: List[str] = Field(
        default=["java", "python", "typescript"],
        description="A list of languages."
    )
    salary_expectation: int = Field(
        default=200000,
        description="Expected salary as an integer number."
    )

    friends: StringListNames = Field(
        default=StringListNames(
            listOfNames=[
                Name(first_name="John", last_name="Doe"),
                Name(first_name="Jane", last_name="Doe"),
                Name(first_name="Jean", last_name="Doe")
            ]
        ),
        description="A list of friends with their names."
    )
    books: List[Book] = Field(
        default=[Book()],
        description="A list of books."
    )

    event_date: MyDate = Field(
        default=MyDate(),
        description="The event date"
    ),

    listOfFruits: List[str] = Field(
        default=["apple", "oranges", "bananas"],
        description="A list of fruits."
    )

    listOfPreferredFruits: List[str] = Field(
        default=["apple", "oranges"],
        description="A list of preferred fruits."
    )

@flow(
    name ="user_flow_application_form",
    display_name="Application form",
    description="Creates a sample application form.",
    input_schema=FlowInput,
)

def build_user_form(aflow: Flow = None) -> Flow:

    user_flow = aflow.userflow()
    user_flow.spec.display_name= "Application"

    # Create form with default submit button and visible cancel button
    user_node_with_form = user_flow.form(
        name="ApplicationForm",
        display_name="Application",
        cancel_button_label="Cancel"
    )
    
    data_map = DataMap()
    data_map.add(Assignment(target_variable="self.input.choices", value_expression="flow.input.salutations"))
 
    #Single-choice: Salutation
    user_node_with_form.single_choice_input_field(name="salutation", label="Salutation", required=True, choices=data_map, 
                                                  show_as_dropdown=True, placeholder_text="Please enter your title")
   
    #Boolean: Married
    user_node_with_form.boolean_input_field(name="married", label="Married", single_checkbox = True, true_label="Married", false_label="Not married")
    
    #Text: Last Name
    user_node_with_form.text_input_field(name="lastName", label="Last name", required=True, placeholder_text="Enter your name here", help_text="Enter name", 
        regex="^[a-zA-Z0-9\s]+$", regex_error_message="No special characters allowed")
    
    #Number: Age
    user_node_with_form.number_input_field(name="age", label="Age", required=True, help_text="Enter your age")

    data_map_salary = DataMap()
    data_map_salary.add(Assignment(target_variable="self.input.default", value_expression="flow.input.salary_expectation"))
    
    #Number: Desired Salary
    user_node_with_form.number_input_field(name="salary", label="Desired salary", is_integer=False, help_text="Your dream salary is here", default=data_map_salary)
  
    data_map_desired_salary = DataMap()
    data_map_desired_salary.add(Assignment(target_variable="self.input.value", value_expression="flow.input.salary_expectation"))

     #Field: Projected salary
    user_node_with_form.field_output_field(name="acknowledge", label="Projected salary", value = data_map_desired_salary)

    #FileUpload
    data_map_min_files = DataMap()
    data_map_min_files.add(Assignment(target_variable="self.input.min_num_files", value_expression="1"))

    data_map_max_files = DataMap()
    data_map_max_files.add(Assignment(target_variable="self.input.max_num_files", value_expression="2"))

    user_node_with_form.file_upload_field(name="credentials", label="Upload credentials", allow_multiple_files=True, file_max_size=256,
                                          min_num_files=data_map_min_files, max_num_files=data_map_max_files)

    #Date: End Date
    data_map_default_date = DataMap()
    data_map_default_date.add(Assignment(target_variable="self.input.default",value_expression="flow.input.event_date.dateEnd"))

    data_map_min_date = DataMap()
    data_map_min_date.add(Assignment(target_variable="self.input.min_date",value_expression="\"2026-01-05\""))
    
    data_map_max_date = DataMap()
    data_map_max_date.add(Assignment(target_variable="self.input.max_date",value_expression="\"2026-01-12\""))

    user_node_with_form.date_input_field(name="endDate", label="End Date", required=True, default=data_map_default_date, 
                                        min_date=data_map_min_date, max_date=data_map_max_date)
  
    data_map_list_source = DataMap()
    data_map_list_source.add(Assignment(target_variable="self.input.choices", value_expression="flow.input.listOfLanguages"))
    
    #Output List: Qualification
    user_node_with_form.list_output_field(name="strength", label="Qualification", choices=data_map_list_source)

    #Output list: Friends table
    data_map_list_friends = DataMap()
    data_map_list_friends.add(Assignment(target_variable="self.input.choices", value_expression="flow.input.friends.listOfNames"))
    user_node_with_form.list_output_field(name="friends", label="Friends", choices=data_map_list_friends, columns={"first_name": "First", "last_name": "Last"})

    #Mult-chocice: List of fruits dowpdown primitives
    data_map_multi_choice = DataMap()
    data_map_multi_choice.add(Assignment(target_variable="self.input.choices", value_expression="flow.input.listOfFruits"))

    data_map_multi_choice_default = DataMap()
    data_map_multi_choice_default.add(Assignment(target_variable="self.input.default", value_expression="flow.input.listOfPreferredFruits"))

    user_node_with_form.multi_choice_input_field(name="multi-choice", label="List of Fruits", required=False, choices=data_map_multi_choice, 
                                                  show_as_dropdown=True, placeholder_text="Please enter your choice", default=data_map_multi_choice_default,
                                                  minItems=1, maxItems=2)
    
    #Mult-chocice: Books dowpdown complex
    data_map_list_books = DataMap()
    data_map_list_books.add(Assignment(target_variable="self.input.choices", value_expression="flow.input.books"))
    user_node_with_form.multi_choice_input_field(name="multi-choice_as_dropdown_1", label="List of Books", required=False, choices=data_map_list_books, 
                                                  show_as_dropdown=True, dropdown_item_column="title", placeholder_text="Please enter your choice")
 
    #Mult-chocice: List of names table
    data_map_list_friends_choice2 = DataMap()
    data_map_list_friends_choice2.add(Assignment(target_variable="self.input.choices", value_expression="flow.input.friends.listOfNames"))

    user_node_with_form.multi_choice_input_field(name="multi-choice_as_table", label="List of Names", required=False, choices=data_map_list_friends_choice2, 
                                                  show_as_dropdown=False, placeholder_text="Please enter your choice", columns={"first_name": "First", "last_name": "Last"} )

    #Input list: Books editable table
    data_map_list_books = DataMap()
    data_map_list_books.add(Assignment(target_variable="self.input.default", value_expression="flow.input.books"))

    user_node_with_form.list_input_field(name="books", label="Books", default=data_map_list_books, columns={"title": "Book Title", "author": "Book Author"})
    #Input list: Fuits editable table
    data_map_list_fruits = DataMap()
    data_map_list_fruits.add(Assignment(target_variable="self.input.default", value_expression="flow.input.listOfFruits"))

    user_node_with_form.list_input_field(name="Fruits", label="Preferred fruits", default=data_map_list_fruits)

    # User field: Select multiple approvers (min 1, max 5)
    data_map_min_users = DataMap()
    data_map_min_users.add(Assignment(target_variable="self.input.min_num_users", value_expression="1"))
    data_map_max_users = DataMap()
    data_map_max_users.add(Assignment(target_variable="self.input.max_num_users", value_expression="5"))
    user_node_with_form.user_input_field(name="approvers", label="Select Approvers", required=True, multiple_users=True,
                                         min_num_users=data_map_min_users, max_num_users=data_map_max_users)

    # User field: Select a single assignee (min/max not applicable for single user)
    user_node_with_form.user_input_field(name="assignee", label="Select Assignee", required=True, multiple_users=False)
    #Output Message: Successful submission
    user_node_with_form.message_output_field(name="success", label="Successful submission", message="Application successfully completed.")
 
    # Add additional buttons using the new API
    save_draft_btn = user_flow.add_button("Save Draft")
    review_btn = user_flow.add_button("Submit for Review")
    
    # Create different nodes for each button action
    submit_node = user_flow.script(
        name="process_submit",
        script='print("Processing full submission...")'
    )
    
    save_draft_node = user_flow.script(
        name="process_save_draft",
        script='print("Saving as draft...")'
    )
    
    review_node = user_flow.script(
        name="process_review",
        script='print("Submitting for review...")'
    )

    # Connect nodes using the new edge API
    user_flow.edge(START, user_node_with_form)
    
    # Connect default "Submit" button using button_label parameter
    user_flow.edge(user_node_with_form, submit_node, button_label="Submit")
    user_flow.edge(submit_node, END)
    
    # Connect "Save Draft" button using Button object
    user_flow.edge(save_draft_btn, save_draft_node)
    user_flow.edge(save_draft_node, END)
    
    # Connect "Submit for Review" button using Button object
    user_flow.edge(review_btn, review_node)
    user_flow.edge(review_node, END)

    # Script to initialize friends list
    init_script = """
flow.input.friends.listOfNames = [
    {"first_name": "John", "last_name": "Doe"},
    {"first_name": "Alice", "last_name": "Smith"},
    {"first_name": "Bob", "last_name": "Johnson"}
]
flow.input.books=[
    { "title": "Shaken", "author":"John Grisham"},
    {"title": "The Client", "author":"John Grisham"},
]
flow.input.listOfFruits = ["apple", "oranges", "bananas"]
"""
    init_data = aflow.script(name="init_data", script=init_script)
    
    # add the user flow to the flow sequence to create the flow edges
    aflow.sequence(START, init_data, user_flow, END)
  
    return aflow
```

### Dynamic form input

Form fields can change based on user actions. You define the dependencies between the user’s interactions and your tools to control dynamic behavior in the form. This includes progressive selection, showing or hiding widgets, and updating widget labels.

Use the following methods to configure dynamic forms:

<AccordionGroup>
  <Accordion title="visibility_behaviour_field">
    Adds a visibility behaviour that shows or hides fields based on conditions.

    <ParamField path="name" type="string" required>
      Unique identifier for this behaviour.
    </ParamField>

    <ParamField path="on_change_to_field" type="string" required>
      Field that triggers evaluation of visibility rules when its value changes.
    </ParamField>

    <ParamField path="rules" type="list[dict]" required>
      List of visibility rules. Each rule specifies a condition and an `impacted_field` that changes visibility.
    </ParamField>

    <ParamField path="display_name" type="string">
      Display name for this behaviour.
    </ParamField>
  </Accordion>

  <Accordion title="label_behaviour_field">
    Adds a label-changing behaviour that updates field labels based on conditions.

    <ParamField path="name" type="string" required>
      Unique identifier for this behaviour.
    </ParamField>

    <ParamField path="on_change_to_field" type="string" required>
      Field that triggers label evaluation when its value changes.
    </ParamField>

    <ParamField path="rules" type="list[dict]" required>
      List of label rules. Each rule includes a condition and an `impacted_field` whose label changes.
    </ParamField>

    <ParamField path="display_name" type="string">
      Display name for this behaviour.
    </ParamField>
  </Accordion>

  <Accordion title="value_source_behaviour_field">
    Adds a value-source behaviour that populates a field using results from a tool.
    Supports a simplified API or a manual API.

    <ParamField path="name" type="string" required>
      Unique identifier for this behaviour.
    </ParamField>

    <ParamField path="on_change_to_field" type="string" required>
      Field that triggers execution of the tool when its value changes.
    </ParamField>

    <ParamField path="impacted_field" type="string" required>
      Field that receives values returned by the tool.
    </ParamField>

    ### Simplified API parameters

    <ParamField path="tool_name" type="string">
      Name of the tool to call, for example `get_states_or_provinces`.
    </ParamField>

    <ParamField path="tool_id" type="string">
      UUID of the tool.
    </ParamField>

    <ParamField path="field_mappings" type="dict[string, string]">
      Mapping of tool parameters to field expressions. For example country maps to `parent.field.country`.
    </ParamField>

    <ParamField path="client" type="any">
      Client instance that enables automatic retrieval of the tool schema.
    </ParamField>

    ### Manual API parameters

    <ParamField path="tool" type="string">
      Tool identifier in name colon UUID format.
    </ParamField>

    <ParamField path="tool_input_schema" type="dict">
      Schema that describes the expected inputs for the tool.
    </ParamField>

    <ParamField path="tool_input_map" type="dict">
      Mapping of input parameters to values or expressions used by the tool.
    </ParamField>

    ### Common optional parameters

    <ParamField path="display_name" type="string">
      Display name for this behaviour.
    </ParamField>
  </Accordion>
</AccordionGroup>

Here is an example that shows how to configure dynamic forms:

```py Python [expandable] theme={null}
from typing import List
from pydantic import BaseModel, Field
from ibm_watsonx_orchestrate.flow_builder.flows import (
    Flow, flow, UserNode, START, END
)
from ibm_watsonx_orchestrate.flow_builder.types import Assignment
from ibm_watsonx_orchestrate.flow_builder.data_map import DataMap
from ibm_watsonx_orchestrate.flow_builder.utils import RuleBuilder


class FlowInput(BaseModel):
    """Input schema for the flow."""
    countries: List[str] = Field(
        default=["USA", "Canada"],
        description="A list of available countries."
    )
    usa_states: List[str] = Field(
        default=["California", "Texas", "New York", "Florida"],
        description="A list of US states."
    )
    canada_provinces: List[str] = Field(
        default=["Ontario", "Quebec", "British Columbia", "Alberta"],
        description="A list of Canadian provinces."
    )
    default_country: str = Field(
        default="USA",
        description="Default country selection."
    )
    default_region: str = Field(
        default="California",
        description="Default region selection."
    )


@flow(
    name="user_activity_with_dynamic_forms_full",
    display_name="Dynamic Form - A simple example",
    description="Demonstrates dynamic form behaviours",
    input_schema=FlowInput,
)
def build_dynamic_form_full(aflow: Flow = None) -> Flow:
    
    # Create user flow
    user_flow = aflow.userflow()
    user_flow.spec.display_name = "Example dynamic form"
    
    # Create form node
    form_node = user_flow.form(
        name="dynamic_form", 
        display_name="Dynamic form example",
        cancel_button_label="Cancel")
    
    #FIELD 1: Country
    country_choices = DataMap()
    country_choices.add(Assignment(
        target_variable="self.input.choices",
        value_expression="flow.input.countries"
    ))
    
    country_default = DataMap()
    country_default.add(Assignment(
        target_variable="self.input.default",
        value_expression="flow.input.default_country"
    ))
    
    form_node.single_choice_input_field(
        name="country",
        label="Country",
        required=False,
        choices=country_choices,
        default=country_default,
        show_as_dropdown=True,
        placeholder_text="Select an option"
    )
    
    #FIELD 2: Visibility Behaviour
    # Controls city and url fields
    form_node.visibility_behaviour_field(
        name="visibility_behaviour",
        on_change_to_field="country",
        rules=[
            RuleBuilder.visibility_rule(
                field_name="country",
                field_value="USA",
                impacted_field="city",
                visible_when_true=True,
                operator="equals"
            ),
            RuleBuilder.visibility_rule(
                field_name="country",
                field_value="Canada",
                impacted_field="url",
                visible_when_true=True,
                operator="equals"
            )
        ],
        display_name="Visibility rule"
    )
    
    # FIELD 3: Label Behaviour
    # Controls code, region, and documents field labels
    form_node.label_behaviour_field(
        name="label_behaviour",
        on_change_to_field="country",
        rules=[
            RuleBuilder.label_rule(
                field_name="country",
                field_value="USA",
                impacted_field="code",
                label_when_true="Zip code",
                label_when_false="Postal code",
                operator="equals"
            ),
            RuleBuilder.label_rule(
                field_name="country",
                field_value="USA",
                impacted_field="region",
                label_when_true="State",
                label_when_false="Province",
                operator="equals"
            ),
            RuleBuilder.label_rule(
                field_name="country",
                field_value="USA",
                impacted_field="documents",
                label_when_true="US W-2 Form",
                label_when_false="Canadian T4 Form",
                operator="equals"
            )
        ],
        display_name="Label rule"
    )
    
    # FIELD 4: Value-Source Behaviour
    # Populates region field options from tool
    form_node.value_source_behaviour_field(
        name="value_source_behaviour",
        on_change_to_field="country",
        impacted_field="region",
        tool_name="get_states_or_provinces",
        tool_id="9f0ecb53-dbd9-4e41-be46-29c8d47d6df8",
        field_mappings={
            "country": "parent.field.country"
        },
        display_name="ProgSelect"
    )
    
    # FIELD 5: Region
    region_choices = DataMap()
    region_choices.add(Assignment(
        target_variable="self.input.choices",
        value_expression='',
        has_no_value=True
    ))
    region_choices.add(Assignment(
        target_variable="self.input.display_text",
        value_expression='',
        has_no_value=True
    ))
    region_choices.add(Assignment(
        target_variable="self.input.display_items",
        value_expression='',
        has_no_value=True
    ))
    
    form_node.single_choice_input_field(
        name="region",
        label="Region",
        required=False,
        choices=region_choices,
        show_as_dropdown=True,
        placeholder_text="Select an option"
    )
    
    # FIELD 6: Code
    form_node.text_input_field(
        name="code",
        label="Code",
        required=False
    )
    
    # FIELD 7: City
    form_node.text_input_field(
        name="city",
        label="City",
        required=False
    )
    
    # FIELD 8: Documents
    form_node.file_upload_field(
        name="documents",
        label="Documents"
    )
    
    # FIELD 9: URL
    form_node.text_input_field(
        name="url",
        label="URL",
        required=False
    )
    
    # Add edges
    user_flow.edge(START, form_node)
    user_flow.edge(form_node, END)
    
    # Script to initialize input data
    init_script = """
# Initialize countries list
flow.input.countries = ["USA", "Canada"]

# Initialize US states
flow.input.usa_states = ["California", "Texas", "New York", "Florida", "Illinois", "Pennsylvania"]

# Initialize Canadian provinces
flow.input.canada_provinces = ["Ontario", "Quebec", "British Columbia", "Alberta", "Manitoba", "Saskatchewan"]

# Set default selections
flow.input.default_country = "USA"
flow.input.default_region = "California"
"""
    init_data = aflow.script(name="init_data", script=init_script)
    
    # Add user flow to main flow with initialization
    aflow.sequence(START, init_data, user_flow, END)
    
    return aflow

```
