Back to all examples

Dynamically add an item to a dropdown list

ReactAngularWeb Components
type Task = {
  value: string;
  label: string;
  mount: GoabDropdownItemMountType;
};

const DEFAULT_TASKS: Task[] = [
    { label: "Finish Report", value: "finish-report", mount: "append" },
    { label: "Attend Meeting", value: "attend-meeting", mount: "append" },
    { label: "Reply Emails", value: "reply-emails", mount: "append" },
  ];

  const [tasks, setTasks] = useState<Task[]>(DEFAULT_TASKS);
  const [newTask, setNewTask] = useState<string>("");
  const [mountType, setMountType] = useState<string>("append");
  const [selectedTask, setSelectedTask] = useState<string>("");
  const [taskError, setTaskError] = useState<boolean>(false);
  const [isReset, setIsReset] = useState<boolean>(false);

  function onMountTypeChange(value: string | undefined) {
    setMountType(value as string);
  }

  function addTask() {
    if (newTask === "") {
      setTaskError(true);
      return;
    }
    setTaskError(false);

    const task: Task = {
      label: newTask,
      value: newTask.toLowerCase().replace(" ", "-"),
      mount: mountType as GoabDropdownItemMountType,
    };
    setTasks([...tasks, task]);
    setNewTask("");
    setIsReset(false);
  }

  function reset() {
    setTasks(DEFAULT_TASKS);
    setMountType("append");
    setNewTask("");
    setSelectedTask("");
    setTaskError(false);
    setIsReset(true);
  }
<GoabFormItem
          requirement="required"
          label="Name of item"
          error={taskError ? "Please enter item name" : undefined}
          helpText="Add an item to the dropdown list below">
          <GoabInput
            onChange={(event: GoabInputOnChangeDetail) => setNewTask(event.value)}
            name="item"
            value={newTask}
          />
        </GoabFormItem>

        <GoabFormItem mt="l" label="Add to">
          <GoabRadioGroup
            name="mountType"
            onChange={(event: GoabRadioGroupOnChangeDetail) => onMountTypeChange(event.value)}
            value={mountType}
            orientation="horizontal">
            <GoabRadioItem value="prepend" label="Start" />
            <GoabRadioItem value="append" label="End" />
          </GoabRadioGroup>
        </GoabFormItem>

        <GoabButtonGroup alignment="start" gap="relaxed" mt="l">
          <GoabButton type="primary" onClick={addTask}>
            Add new item
          </GoabButton>
          <GoabButton type="tertiary" onClick={reset}>
            Reset list
          </GoabButton>
        </GoabButtonGroup>

        <GoabDivider mt="l" />

        <GoabFormItem mt="l" label="All items">
          <div style={{ width: isReset ? "320px" : "auto" }}>
            <GoabDropdown
              key={tasks.length}
              onChange={(event: GoabDropdownOnChangeDetail) =>
                setSelectedTask(event.value as string)
              }
              value={selectedTask}
              name="selectedTask">
              {tasks.map(task => (
                <GoabDropdownItem
                  key={task.value}
                  value={task.value}
                  mountType={task.mount}
                  label={task.label}
                />
              ))}
            </GoabDropdown>
          </div>
      </GoabFormItem>

Allow users to add new items to a dropdown list dynamically.

When to use

Use this pattern when:

  • Users need to add custom options to a predefined list
  • The list of options can grow based on user input
  • You want to provide flexibility while maintaining structure

Considerations

  • Use the mountType prop to control where new items appear (prepend or append)
  • Validate input before adding to prevent empty or duplicate entries
  • Provide a reset option to restore the original list
  • Show clear feedback when items are added successfully