diff --git a/frontend/src/metabase-lib/metadata/utils/fields.ts b/frontend/src/metabase-lib/metadata/utils/fields.ts
index 545df4ffccf9f12234691ad9bc01a1f6783ce4fa..c9e1367893a8024e1cc96a54f072423aa6ed5849 100644
--- a/frontend/src/metabase-lib/metadata/utils/fields.ts
+++ b/frontend/src/metabase-lib/metadata/utils/fields.ts
@@ -49,3 +49,7 @@ function getFieldIdentifier(field: Field): number | string {
 
   return id || name;
 }
+
+export function isVirtualFieldId(id: Field["id"]) {
+  return typeof id !== "number";
+}
diff --git a/frontend/src/metabase-lib/parameters/utils/parameter-fields.ts b/frontend/src/metabase-lib/parameters/utils/parameter-fields.ts
new file mode 100644
index 0000000000000000000000000000000000000000..60238fffa54739dbb50e71fb2f1915e4a4c33b71
--- /dev/null
+++ b/frontend/src/metabase-lib/parameters/utils/parameter-fields.ts
@@ -0,0 +1,23 @@
+import { isVirtualFieldId } from "metabase-lib/metadata/utils/fields";
+import {
+  FieldFilterUiParameter,
+  UiParameter,
+} from "metabase-lib/parameters/types";
+
+export const hasFields = (
+  parameter: UiParameter,
+): parameter is FieldFilterUiParameter => {
+  return (parameter as FieldFilterUiParameter).fields != null;
+};
+
+export const getFields = (parameter: UiParameter) => {
+  if (hasFields(parameter)) {
+    return parameter.fields;
+  } else {
+    return [];
+  }
+};
+
+export const getNonVirtualFields = (parameter: UiParameter) => {
+  return getFields(parameter).filter(field => !isVirtualFieldId(field.id));
+};
diff --git a/frontend/src/metabase-lib/parameters/utils/parameter-source.ts b/frontend/src/metabase-lib/parameters/utils/parameter-source.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3d04f6c013f34696a14d711add8676908dba8e7e
--- /dev/null
+++ b/frontend/src/metabase-lib/parameters/utils/parameter-source.ts
@@ -0,0 +1,27 @@
+import { ValuesSourceConfig, ValuesSourceType } from "metabase-types/api";
+
+export const isValidSourceConfig = (
+  sourceType: ValuesSourceType,
+  sourceConfig: ValuesSourceConfig,
+) => {
+  switch (sourceType) {
+    case "card":
+      return sourceConfig.card_id != null && sourceConfig.value_field != null;
+    case "static-list":
+      return sourceConfig.values != null && sourceConfig.values.length > 0;
+    default:
+      return true;
+  }
+};
+
+export const getDefaultSourceConfig = (
+  sourceType: ValuesSourceType,
+  sourceValues?: string[],
+) => {
+  switch (sourceType) {
+    case "static-list":
+      return { values: sourceValues };
+    default:
+      return {};
+  }
+};
diff --git a/frontend/src/metabase-types/api/mocks/parameters.ts b/frontend/src/metabase-types/api/mocks/parameters.ts
index ceb6e138021a6b32936ad89843061006fe65a746..ce15e59058072abcfbf72d80d0a5bd8eda7b2801 100644
--- a/frontend/src/metabase-types/api/mocks/parameters.ts
+++ b/frontend/src/metabase-types/api/mocks/parameters.ts
@@ -1,4 +1,4 @@
-import { Parameter, ValuesSourceConfig } from "metabase-types/api";
+import { Parameter } from "metabase-types/api";
 
 export const createMockParameter = (opts?: Partial<Parameter>): Parameter => ({
   id: "1",
@@ -7,9 +7,3 @@ export const createMockParameter = (opts?: Partial<Parameter>): Parameter => ({
   slug: "text",
   ...opts,
 });
-
-export const createMockValuesSourceConfig = (
-  opts?: Partial<ValuesSourceConfig>,
-): ValuesSourceConfig => ({
-  ...opts,
-});
diff --git a/frontend/src/metabase/containers/DataPicker/DataPickerContainer.tsx b/frontend/src/metabase/containers/DataPicker/DataPickerContainer.tsx
index e6b2214550e0464da739a9762bde183f9f0114ad..5fbf9c9ab41f43fee612fbd3ac09ab77138892db 100644
--- a/frontend/src/metabase/containers/DataPicker/DataPickerContainer.tsx
+++ b/frontend/src/metabase/containers/DataPicker/DataPickerContainer.tsx
@@ -54,6 +54,7 @@ function mapStateToProps(state: State) {
 }
 
 function DataPicker({
+  value,
   databases,
   search: modelLookupResult,
   filters: customFilters = {},
@@ -114,7 +115,7 @@ function DataPicker({
   );
 
   useOnMount(() => {
-    if (dataTypes.length === 1) {
+    if (dataTypes.length === 1 && value.type !== dataTypes[0].id) {
       handleDataTypeChange(dataTypes[0].id);
     }
   });
@@ -133,6 +134,7 @@ function DataPicker({
   return (
     <DataPickerView
       {...props}
+      value={value}
       dataTypes={dataTypes}
       searchQuery={search.query}
       hasDataAccess={hasDataAccess}
diff --git a/frontend/src/metabase/containers/DataPicker/tests/DataPicker-RawData.unit.spec.ts b/frontend/src/metabase/containers/DataPicker/tests/DataPicker-RawData.unit.spec.ts
index db37ba4d10032208040edaf20d60b03211441578..d43bb01762c6bae701a8afe2fdf16ad21c3e5745 100644
--- a/frontend/src/metabase/containers/DataPicker/tests/DataPicker-RawData.unit.spec.ts
+++ b/frontend/src/metabase/containers/DataPicker/tests/DataPicker-RawData.unit.spec.ts
@@ -114,6 +114,9 @@ describe("DataPicker — picking raw data", () => {
           schemaId: generateSchemaId(SAMPLE_DATABASE.id, "PUBLIC"),
           tableIds: [SAMPLE_DATABASE.PRODUCTS.id],
         },
+        filters: {
+          types: type => type === "raw-data",
+        },
       });
 
       const tableListItem = await screen.findByRole("menuitem", {
diff --git a/frontend/src/metabase/parameters/components/CardValuesSourceModal/CardStepModal.styled.tsx b/frontend/src/metabase/parameters/components/CardValuesSourceModal/CardStepModal.styled.tsx
deleted file mode 100644
index 31f5ea0709728e3081f9a440bfa53007f63798a8..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/CardValuesSourceModal/CardStepModal.styled.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import styled from "@emotion/styled";
-
-export const SearchInputContainer = styled.div`
-  margin-bottom: 1.5rem;
-`;
-
-export const DataPickerContainer = styled.div`
-  height: 50vh;
-  overflow-y: auto;
-`;
diff --git a/frontend/src/metabase/parameters/components/CardValuesSourceModal/CardStepModal.tsx b/frontend/src/metabase/parameters/components/CardValuesSourceModal/CardStepModal.tsx
deleted file mode 100644
index e08dff873254c24babd7e25b5d596970a28a263d..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/CardValuesSourceModal/CardStepModal.tsx
+++ /dev/null
@@ -1,155 +0,0 @@
-import React, { ChangeEvent, useCallback } from "react";
-import { connect } from "react-redux";
-import { t } from "ttag";
-import _ from "underscore";
-import Button from "metabase/core/components/Button/Button";
-import Input from "metabase/core/components/Input";
-import ModalContent from "metabase/components/ModalContent";
-import DataPicker, {
-  DataPickerValue,
-  useDataPicker,
-  useDataPickerValue,
-} from "metabase/containers/DataPicker";
-import Questions from "metabase/entities/questions";
-import Collections from "metabase/entities/collections";
-import { getMetadata } from "metabase/selectors/metadata";
-import { Card, CardId, Collection } from "metabase-types/api";
-import { State } from "metabase-types/store";
-import Question from "metabase-lib/Question";
-import {
-  getCollectionVirtualSchemaId,
-  getQuestionIdFromVirtualTableId,
-  getQuestionVirtualTableId,
-} from "metabase-lib/metadata/utils/saved-questions";
-import {
-  DataPickerContainer,
-  SearchInputContainer,
-} from "./CardStepModal.styled";
-
-interface CardStepModalOwnProps {
-  cardId: CardId | undefined;
-  onChangeCard: (cardId: CardId | undefined) => void;
-  onSubmit: () => void;
-  onClose: () => void;
-}
-
-interface CardStepModalCardProps {
-  card: Card | undefined;
-}
-
-interface CardStepModalCollectionProps {
-  collection: Collection | undefined;
-}
-
-interface CardStepModalStateProps {
-  question: Question | undefined;
-}
-
-type CardStepModalProps = CardStepModalOwnProps &
-  CardStepModalCardProps &
-  CardStepModalCollectionProps &
-  CardStepModalStateProps;
-
-const CardStepModal = ({
-  question,
-  collection,
-  onChangeCard,
-  onSubmit,
-  onClose,
-}: CardStepModalProps): JSX.Element => {
-  const initialValue = getInitialValue(question, collection);
-  const [value, setValue] = useDataPickerValue(initialValue);
-  const cardId = getCardIdFromValue(value);
-
-  const handleSubmit = useCallback(() => {
-    onChangeCard(cardId);
-    onSubmit();
-  }, [cardId, onChangeCard, onSubmit]);
-
-  return (
-    <ModalContent
-      title={t`Pick a model or question to use for the values of this widget`}
-      footer={[
-        <Button key="cancel" onClick={onClose}>{t`Cancel`}</Button>,
-        <Button
-          key="submit"
-          primary
-          disabled={cardId == null}
-          onClick={handleSubmit}
-        >{t`Select column`}</Button>,
-      ]}
-      onClose={onClose}
-    >
-      <DataPicker.Provider>
-        <DataPickerSearchInput />
-        <DataPickerContainer>
-          <DataPicker value={value} onChange={setValue} />
-        </DataPickerContainer>
-      </DataPicker.Provider>
-    </ModalContent>
-  );
-};
-
-const DataPickerSearchInput = () => {
-  const { search } = useDataPicker();
-  const { query, setQuery } = search;
-
-  const handleChange = useCallback(
-    (event: ChangeEvent<HTMLInputElement>) => {
-      setQuery(event.target.value);
-    },
-    [setQuery],
-  );
-
-  return (
-    <SearchInputContainer>
-      <Input
-        value={query}
-        placeholder={t`Search for a question or model`}
-        leftIcon="search"
-        fullWidth
-        onChange={handleChange}
-      />
-    </SearchInputContainer>
-  );
-};
-
-const getInitialValue = (
-  question?: Question,
-  collection?: Collection,
-): Partial<DataPickerValue> | undefined => {
-  if (question) {
-    const id = question.id();
-    const isDatasets = question.isDataset();
-
-    return {
-      type: isDatasets ? "models" : "questions",
-      schemaId: getCollectionVirtualSchemaId(collection, { isDatasets }),
-      collectionId: collection?.id,
-      tableIds: [getQuestionVirtualTableId(id)],
-    };
-  }
-};
-
-const getCardIdFromValue = ({ tableIds }: DataPickerValue) => {
-  if (tableIds.length) {
-    const cardId = getQuestionIdFromVirtualTableId(tableIds[0]);
-    if (cardId != null) {
-      return cardId;
-    }
-  }
-};
-
-export default _.compose(
-  Questions.load({
-    id: (state: State, { cardId }: CardStepModalOwnProps) => cardId,
-    entityAlias: "card",
-  }),
-  Collections.load({
-    id: (state: State, { card }: CardStepModalCardProps) =>
-      card?.collection_id ?? "root",
-  }),
-  connect((state: State, { card }: CardStepModalCardProps) => ({
-    question: card ? new Question(card, getMetadata(state)) : undefined,
-  })),
-)(CardStepModal);
diff --git a/frontend/src/metabase/parameters/components/CardValuesSourceModal/CardValuesSourceModal.tsx b/frontend/src/metabase/parameters/components/CardValuesSourceModal/CardValuesSourceModal.tsx
deleted file mode 100644
index 33d9b154f4f081e891a369726dd0311fe159b472..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/CardValuesSourceModal/CardValuesSourceModal.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import React, { useCallback, useState } from "react";
-import { ValuesSourceConfig } from "metabase-types/api";
-import CardStepModal from "./CardStepModal";
-import FieldStepModal from "./FieldStepModal";
-
-type ModalStep = "card" | "field";
-
-export interface CardValuesSourceModalProps {
-  sourceConfig: ValuesSourceConfig;
-  onChangeSourceConfig: (sourceConfig: ValuesSourceConfig) => void;
-  onClose: () => void;
-}
-
-const CardValuesSourceModal = ({
-  sourceConfig,
-  onChangeSourceConfig,
-  onClose,
-}: CardValuesSourceModalProps): JSX.Element | null => {
-  const [step, setStep] = useState<ModalStep>("card");
-  const [cardId, setCardId] = useState(sourceConfig.card_id);
-  const [fieldReference, setFieldReference] = useState(
-    sourceConfig.value_field,
-  );
-
-  const handleCardSubmit = useCallback(() => {
-    setStep("field");
-  }, []);
-
-  const handleFieldSubmit = useCallback(() => {
-    onChangeSourceConfig({ card_id: cardId, value_field: fieldReference });
-    onClose();
-  }, [cardId, fieldReference, onChangeSourceConfig, onClose]);
-
-  const handleFieldCancel = useCallback(() => {
-    setStep("card");
-  }, []);
-
-  switch (step) {
-    case "card":
-      return (
-        <CardStepModal
-          cardId={cardId}
-          onChangeCard={setCardId}
-          onSubmit={handleCardSubmit}
-          onClose={onClose}
-        />
-      );
-    case "field":
-      return (
-        <FieldStepModal
-          cardId={cardId}
-          fieldReference={fieldReference}
-          onChangeField={setFieldReference}
-          onSubmit={handleFieldSubmit}
-          onCancel={handleFieldCancel}
-          onClose={onClose}
-        />
-      );
-    default:
-      return null;
-  }
-};
-
-export default CardValuesSourceModal;
diff --git a/frontend/src/metabase/parameters/components/CardValuesSourceModal/FieldStepModal.tsx b/frontend/src/metabase/parameters/components/CardValuesSourceModal/FieldStepModal.tsx
deleted file mode 100644
index a32b1d224b34bd850e962da58973f0fb17646e79..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/CardValuesSourceModal/FieldStepModal.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import React, { useCallback, useMemo } from "react";
-import { t } from "ttag";
-import _ from "underscore";
-import Button from "metabase/core/components/Button/Button";
-import Select, {
-  Option,
-  SelectChangeEvent,
-} from "metabase/core/components/Select";
-import ModalContent from "metabase/components/ModalContent";
-import Tables from "metabase/entities/tables";
-import { CardId } from "metabase-types/api";
-import { State } from "metabase-types/store";
-import Field from "metabase-lib/metadata/Field";
-import Table from "metabase-lib/metadata/Table";
-import { getQuestionVirtualTableId } from "metabase-lib/metadata/utils/saved-questions";
-import { ModalBody } from "./FieldStepModal.styled";
-
-interface FieldStepModalOwnProps {
-  cardId: CardId | undefined;
-  fieldReference: unknown[] | undefined;
-  onChangeField: (field: unknown[]) => void;
-  onSubmit: () => void;
-  onCancel: () => void;
-  onClose: () => void;
-}
-
-interface FieldStepModalTableProps {
-  table: Table;
-}
-
-type FieldStepModalProps = FieldStepModalOwnProps & FieldStepModalTableProps;
-
-const FieldStepModal = ({
-  table,
-  fieldReference,
-  onChangeField,
-  onSubmit,
-  onCancel,
-  onClose,
-}: FieldStepModalProps): JSX.Element => {
-  const fields = useMemo(() => {
-    return getSupportedFields(table);
-  }, [table]);
-
-  const selectedField = useMemo(() => {
-    return fieldReference && getFieldByReference(fields, fieldReference);
-  }, [fields, fieldReference]);
-
-  const handleChange = useCallback(
-    (event: SelectChangeEvent<Field>) => {
-      onChangeField(event.target.value.reference());
-    },
-    [onChangeField],
-  );
-
-  return (
-    <ModalContent
-      title={t`Which column from ${table.displayName()} should be used`}
-      footer={[
-        <Button key="cancel" onClick={onCancel}>{t`Back`}</Button>,
-        <Button
-          key="submit"
-          primary
-          disabled={!selectedField}
-          onClick={onSubmit}
-        >{t`Done`}</Button>,
-      ]}
-      onClose={onClose}
-    >
-      <ModalBody>
-        <Select
-          value={selectedField}
-          placeholder={t`Pick a column`}
-          onChange={handleChange}
-        >
-          {fields.map((field, index) => (
-            <Option key={index} name={field.displayName()} value={field} />
-          ))}
-        </Select>
-      </ModalBody>
-    </ModalContent>
-  );
-};
-
-const getFieldByReference = (fields: Field[], fieldReference: unknown[]) => {
-  return fields.find(field => _.isEqual(field.reference(), fieldReference));
-};
-
-const getSupportedFields = (table: Table) => {
-  return table.fields.filter(field => field.isString());
-};
-
-export default Tables.load({
-  id: (state: State, { cardId }: FieldStepModalOwnProps) =>
-    getQuestionVirtualTableId(cardId),
-  requestType: "fetchMetadata",
-})(FieldStepModal);
diff --git a/frontend/src/metabase/parameters/components/CardValuesSourceModal/index.ts b/frontend/src/metabase/parameters/components/CardValuesSourceModal/index.ts
deleted file mode 100644
index 9d270024f7990fd0bdd5456f564ec4e3d2d717e0..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/CardValuesSourceModal/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./CardValuesSourceModal";
diff --git a/frontend/src/metabase/parameters/components/FormattedParameterValue/FormattedParameterValue.tsx b/frontend/src/metabase/parameters/components/FormattedParameterValue/FormattedParameterValue.tsx
index 8d08be9be8073a85c5472c155d9b228d04585c3b..3fc3fb69359642264fa4cbacc7be393c186c9f44 100644
--- a/frontend/src/metabase/parameters/components/FormattedParameterValue/FormattedParameterValue.tsx
+++ b/frontend/src/metabase/parameters/components/FormattedParameterValue/FormattedParameterValue.tsx
@@ -2,10 +2,8 @@ import React from "react";
 
 import { formatParameterValue } from "metabase/parameters/utils/formatting";
 import ParameterFieldWidgetValue from "metabase/parameters/components/widgets/ParameterFieldWidget/ParameterFieldWidgetValue/ParameterFieldWidgetValue";
-import {
-  UiParameter,
-  FieldFilterUiParameter,
-} from "metabase-lib/parameters/types";
+import { UiParameter } from "metabase-lib/parameters/types";
+import { hasFields } from "metabase-lib/parameters/utils/parameter-fields";
 import { isDateParameter } from "metabase-lib/parameters/utils/parameter-type";
 
 type FormattedParameterValueProps = {
@@ -32,10 +30,4 @@ function FormattedParameterValue({
   return <span>{formatParameterValue(value, parameter)}</span>;
 }
 
-function hasFields(
-  parameter: UiParameter,
-): parameter is FieldFilterUiParameter {
-  return !!(parameter as FieldFilterUiParameter).fields;
-}
-
 export default FormattedParameterValue;
diff --git a/frontend/src/metabase/parameters/components/ListValuesSourceModal/ListValuesSourceModal.styled.tsx b/frontend/src/metabase/parameters/components/ListValuesSourceModal/ListValuesSourceModal.styled.tsx
deleted file mode 100644
index 943bdf672834d728ce9783c0f18f102b1708eedc..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/ListValuesSourceModal/ListValuesSourceModal.styled.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import styled from "@emotion/styled";
-import { color } from "metabase/lib/colors";
-import TextArea from "metabase/core/components/TextArea";
-
-export const ModalMessage = styled.div`
-  color: ${color("text-medium")};
-  margin-bottom: 1rem;
-`;
-
-export const ModalTextArea = styled(TextArea)`
-  resize: vertical;
-`;
diff --git a/frontend/src/metabase/parameters/components/ListValuesSourceModal/ListValuesSourceModal.tsx b/frontend/src/metabase/parameters/components/ListValuesSourceModal/ListValuesSourceModal.tsx
deleted file mode 100644
index 978f70fb64a1dedab6a2fa00e31dad4983e269f2..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/ListValuesSourceModal/ListValuesSourceModal.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import React, { ChangeEvent, useCallback, useState } from "react";
-import { t } from "ttag";
-import Button from "metabase/core/components/Button";
-import ModalContent from "metabase/components/ModalContent";
-import { ValuesSourceConfig } from "metabase-types/api";
-import { ModalMessage, ModalTextArea } from "./ListValuesSourceModal.styled";
-
-const NEW_LINE = "\n";
-const PLACEHOLDER = [t`banana`, t`orange`].join(NEW_LINE);
-
-export interface ListValuesSourceModalProps {
-  sourceConfig: ValuesSourceConfig;
-  onChangeSourceConfig: (sourceConfig: ValuesSourceConfig) => void;
-  onClose: () => void;
-}
-
-const ListValuesSourceModal = ({
-  sourceConfig,
-  onChangeSourceConfig,
-  onClose,
-}: ListValuesSourceModalProps): JSX.Element => {
-  const [value, setValue] = useState(getInputValue(sourceConfig.values));
-  const isEmpty = !value.trim().length;
-
-  const handleChange = useCallback(
-    (event: ChangeEvent<HTMLTextAreaElement>) => {
-      setValue(event.target.value);
-    },
-    [],
-  );
-
-  const handleSubmit = useCallback(() => {
-    onChangeSourceConfig({ values: getSourceValues(value) });
-    onClose();
-  }, [value, onChangeSourceConfig, onClose]);
-
-  return (
-    <ModalContent
-      title={t`Create a custom list`}
-      footer={[
-        <Button key="cancel" onClick={onClose}>{t`Cancel`}</Button>,
-        <Button
-          key="submit"
-          primary
-          disabled={isEmpty}
-          onClick={handleSubmit}
-        >{t`Done`}</Button>,
-      ]}
-      onClose={onClose}
-    >
-      <div>
-        <ModalMessage>{t`Enter one value per line.`}</ModalMessage>
-        <ModalTextArea
-          value={value}
-          placeholder={PLACEHOLDER}
-          autoFocus
-          fullWidth
-          onChange={handleChange}
-        />
-      </div>
-    </ModalContent>
-  );
-};
-
-const getInputValue = (values?: string[]) => {
-  return values?.join(NEW_LINE) ?? "";
-};
-
-const getSourceValues = (value: string) => {
-  return value
-    .split(NEW_LINE)
-    .map(line => line.trim())
-    .filter(line => line.length > 0);
-};
-
-export default ListValuesSourceModal;
diff --git a/frontend/src/metabase/parameters/components/ListValuesSourceModal/ListValuesSourceModal.unit.spec.tsx b/frontend/src/metabase/parameters/components/ListValuesSourceModal/ListValuesSourceModal.unit.spec.tsx
deleted file mode 100644
index 2188d327ca68966ccc0618bcadd6c589596ded38..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/ListValuesSourceModal/ListValuesSourceModal.unit.spec.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import React from "react";
-import { render, screen } from "@testing-library/react";
-import userEvent, { specialChars } from "@testing-library/user-event";
-import { createMockValuesSourceConfig } from "metabase-types/api/mocks";
-import ListValuesSourceModal, {
-  ListValuesSourceModalProps,
-} from "./ListValuesSourceModal";
-
-describe("ListValuesSourceModal", () => {
-  it("should trim and set source values", () => {
-    const props = getProps();
-
-    render(<ListValuesSourceModal {...props} />);
-
-    const input = screen.getByRole("textbox");
-    userEvent.type(input, `Gadget ${specialChars.enter}`);
-    userEvent.type(input, `Widget ${specialChars.enter}`);
-    userEvent.click(screen.getByText("Done"));
-
-    expect(props.onChangeSourceConfig).toHaveBeenCalledWith({
-      values: ["Gadget", "Widget"],
-    });
-  });
-
-  it("should not allow to submit empty values", () => {
-    const props = getProps({
-      sourceConfig: createMockValuesSourceConfig({
-        values: ["Gadget", "Gizmo"],
-      }),
-    });
-
-    render(<ListValuesSourceModal {...props} />);
-    userEvent.clear(screen.getByRole("textbox"));
-
-    expect(screen.getByRole("button", { name: "Done" })).toBeDisabled();
-  });
-});
-
-const getProps = (
-  opts?: Partial<ListValuesSourceModalProps>,
-): ListValuesSourceModalProps => ({
-  sourceConfig: createMockValuesSourceConfig(),
-  onChangeSourceConfig: jest.fn(),
-  onClose: jest.fn(),
-  ...opts,
-});
diff --git a/frontend/src/metabase/parameters/components/ListValuesSourceModal/index.ts b/frontend/src/metabase/parameters/components/ListValuesSourceModal/index.ts
deleted file mode 100644
index 93b838895a5dfc4530955158158c1d13acbbea13..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/ListValuesSourceModal/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from "./ListValuesSourceModal";
diff --git a/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.styled.tsx b/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.styled.tsx
index 364520e5ab2cd25318c507586e2a37d3ce3b17e1..095e988d5abc6557321fe086002c970a0e5f0dbf 100644
--- a/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.styled.tsx
+++ b/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.styled.tsx
@@ -13,6 +13,7 @@ export const SettingSection = styled.div`
 
 export const SettingLabel = styled.label`
   display: block;
+  color: ${color("text-medium")};
   margin-bottom: 0.5rem;
   font-weight: bold;
 `;
diff --git a/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.tsx b/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.tsx
index 6722cc369568dffe431c0ef301b4fef084f0bc30..1e0dd14780a8c6d7c6ecdc2a743a9f372c4c74da 100644
--- a/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.tsx
+++ b/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.tsx
@@ -1,12 +1,6 @@
-import React, {
-  ChangeEvent,
-  FocusEvent,
-  useCallback,
-  useLayoutEffect,
-  useState,
-} from "react";
+import React, { ChangeEvent, useCallback } from "react";
 import { t } from "ttag";
-import Input from "metabase/core/components/Input";
+import InputBlurChange from "metabase/components/InputBlurChange";
 import Radio from "metabase/core/components/Radio";
 import { ValuesSourceConfig, ValuesSourceType } from "metabase-types/api";
 import { UiParameter } from "metabase-lib/parameters/types";
@@ -42,21 +36,31 @@ export interface ParameterSettingsProps {
 const ParameterSettings = ({
   parameter,
   onChangeName,
-  onChangeSourceType,
-  onChangeSourceConfig,
   onChangeDefaultValue,
   onChangeIsMultiSelect,
+  onChangeSourceType,
+  onChangeSourceConfig,
   onRemoveParameter,
 }: ParameterSettingsProps): JSX.Element => {
+  const handleNameChange = useCallback(
+    (event: ChangeEvent<HTMLInputElement>) => {
+      onChangeName(event.target.value);
+    },
+    [onChangeName],
+  );
+
   return (
     <SettingsRoot>
       <SettingSection>
         <SettingLabel>{t`Label`}</SettingLabel>
-        <ParameterInput initialValue={parameter.name} onChange={onChangeName} />
+        <InputBlurChange
+          value={parameter.name}
+          onBlurChange={handleNameChange}
+        />
       </SettingSection>
       {canUseCustomSource(parameter) && (
         <SettingSection>
-          <SettingLabel>{t`Options to pick from`}</SettingLabel>
+          <SettingLabel>{t`How should users filter on this column?`}</SettingLabel>
           <ParameterSourceSettings
             parameter={parameter}
             onChangeSourceType={onChangeSourceType}
@@ -92,37 +96,4 @@ const ParameterSettings = ({
   );
 };
 
-interface ParameterInputProps {
-  initialValue: string;
-  onChange: (value: string) => void;
-}
-
-const ParameterInput = ({ initialValue, onChange }: ParameterInputProps) => {
-  const [value, setValue] = useState(initialValue);
-
-  useLayoutEffect(() => {
-    setValue(initialValue);
-  }, [initialValue]);
-
-  const handleChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
-    setValue(event.target.value);
-  }, []);
-
-  const handleBlur = useCallback(
-    (event: FocusEvent<HTMLInputElement>) => {
-      onChange(event.target.value);
-    },
-    [onChange],
-  );
-
-  return (
-    <Input
-      value={value}
-      fullWidth
-      onChange={handleChange}
-      onBlur={handleBlur}
-    />
-  );
-};
-
 export default ParameterSettings;
diff --git a/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.unit.spec.tsx b/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.unit.spec.tsx
deleted file mode 100644
index cfeb4a64b44dd6635d1bdfbf57cd71de324bd9bc..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/ParameterSettings/ParameterSettings.unit.spec.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from "react";
-import { render, screen } from "@testing-library/react";
-import { createMockUiParameter } from "metabase-lib/mocks";
-import ParameterSettings, { ParameterSettingsProps } from "./ParameterSettings";
-
-describe("ParameterSettings", () => {
-  it("should show source settings only for string dropdowns", () => {
-    const props = getProps({
-      parameter: createMockUiParameter({
-        type: "string/=",
-      }),
-    });
-
-    render(<ParameterSettings {...props} />);
-
-    expect(screen.getByText("Options to pick from")).toBeInTheDocument();
-  });
-
-  it("should not show source settings for other parameter types", () => {
-    const props = getProps({
-      parameter: createMockUiParameter({
-        type: "string/!=",
-      }),
-    });
-
-    render(<ParameterSettings {...props} />);
-
-    expect(screen.queryByText("Options to pick from")).not.toBeInTheDocument();
-  });
-});
-
-const getProps = (
-  opts?: Partial<ParameterSettingsProps>,
-): ParameterSettingsProps => ({
-  parameter: createMockUiParameter(),
-  onChangeName: jest.fn(),
-  onChangeDefaultValue: jest.fn(),
-  onChangeIsMultiSelect: jest.fn(),
-  onChangeSourceType: jest.fn(),
-  onChangeSourceConfig: jest.fn(),
-  onRemoveParameter: jest.fn(),
-  ...opts,
-});
diff --git a/frontend/src/metabase/parameters/components/ParameterSourceSettings/ParameterSourceSettings.tsx b/frontend/src/metabase/parameters/components/ParameterSourceSettings/ParameterSourceSettings.tsx
index 7ba3740129f58200ba22fde77a67d0d8f92ac975..cdc5e3f6a51ad37ac5568ced65a267522ed22918 100644
--- a/frontend/src/metabase/parameters/components/ParameterSourceSettings/ParameterSourceSettings.tsx
+++ b/frontend/src/metabase/parameters/components/ParameterSourceSettings/ParameterSourceSettings.tsx
@@ -2,14 +2,9 @@ import React, { useCallback, useMemo, useState } from "react";
 import { t } from "ttag";
 import Radio from "metabase/core/components/Radio/Radio";
 import Modal from "metabase/components/Modal";
-import {
-  getSourceConfig,
-  getSourceType,
-} from "metabase/parameters/utils/dashboards";
 import { ValuesSourceConfig, ValuesSourceType } from "metabase-types/api";
 import { UiParameter } from "metabase-lib/parameters/types";
-import CardValuesSourceModal from "../CardValuesSourceModal";
-import ListValuesSourceModal from "../ListValuesSourceModal";
+import ValuesSourceModal from "../ValuesSourceModal";
 import {
   RadioLabelButton,
   RadioLabelRoot,
@@ -27,64 +22,33 @@ const ParameterSourceSettings = ({
   onChangeSourceType,
   onChangeSourceConfig,
 }: ParameterSourceSettingsProps): JSX.Element => {
-  const sourceType = getSourceType(parameter);
-  const sourceConfig = getSourceConfig(parameter);
-  const [editingType, setEditingType] = useState<ValuesSourceType>();
+  const [isModalOpened, setIsModalOpened] = useState(false);
 
-  const radioOptions = useMemo(
-    () => getRadioOptions(sourceType, setEditingType),
-    [sourceType],
-  );
+  const radioOptions = useMemo(() => {
+    return getRadioOptions(() => setIsModalOpened(true));
+  }, []);
 
-  const handleSourceTypeChange = useCallback(
-    (sourceType: ValuesSourceType) => {
-      if (sourceType == null) {
-        onChangeSourceType(sourceType);
-        onChangeSourceConfig({});
-      } else {
-        setEditingType(sourceType);
-      }
+  const handleSubmit = useCallback(
+    (sourceType: ValuesSourceType, sourceConfig: ValuesSourceConfig) => {
+      onChangeSourceType(sourceType);
+      onChangeSourceConfig(sourceConfig);
     },
     [onChangeSourceType, onChangeSourceConfig],
   );
 
-  const handleSourceConfigChange = useCallback(
-    (sourceConfig: ValuesSourceConfig) => {
-      if (editingType) {
-        onChangeSourceType(editingType);
-        onChangeSourceConfig(sourceConfig);
-      }
-    },
-    [editingType, onChangeSourceType, onChangeSourceConfig],
-  );
-
-  const handleClose = useCallback(() => {
-    setEditingType(undefined);
+  const handleModalClose = useCallback(() => {
+    setIsModalOpened(false);
   }, []);
 
   return (
     <>
-      <Radio
-        value={sourceType}
-        options={radioOptions}
-        vertical
-        onChange={handleSourceTypeChange}
-      />
-      {editingType === "card" && (
-        <Modal medium onClose={handleClose}>
-          <CardValuesSourceModal
-            sourceConfig={sourceConfig}
-            onChangeSourceConfig={handleSourceConfigChange}
-            onClose={handleClose}
-          />
-        </Modal>
-      )}
-      {editingType === "static-list" && (
-        <Modal onClose={handleClose}>
-          <ListValuesSourceModal
-            sourceConfig={sourceConfig}
-            onChangeSourceConfig={handleSourceConfigChange}
-            onClose={handleClose}
+      <Radio value="list" options={radioOptions} vertical />
+      {isModalOpened && (
+        <Modal medium onClose={handleModalClose}>
+          <ValuesSourceModal
+            parameter={parameter}
+            onSubmit={handleSubmit}
+            onClose={handleModalClose}
           />
         </Modal>
       )}
@@ -94,58 +58,23 @@ const ParameterSourceSettings = ({
 
 interface RadioLabelProps {
   title: string;
-  isSelected?: boolean;
-  onEditClick?: () => void;
+  onEditClick: () => void;
 }
 
-const RadioLabel = ({
-  title,
-  isSelected,
-  onEditClick,
-}: RadioLabelProps): JSX.Element => {
+const RadioLabel = ({ title, onEditClick }: RadioLabelProps): JSX.Element => {
   return (
     <RadioLabelRoot>
       <RadioLabelTitle>{title}</RadioLabelTitle>
-      {isSelected && onEditClick && (
-        <RadioLabelButton onClick={onEditClick}>{t`Edit`}</RadioLabelButton>
-      )}
+      <RadioLabelButton onClick={onEditClick}>{t`Edit`}</RadioLabelButton>
     </RadioLabelRoot>
   );
 };
 
-const getRadioOptions = (
-  sourceType: ValuesSourceType,
-  onEdit: (sourceType: ValuesSourceType) => void,
-) => {
+const getRadioOptions = (onEditClick: () => void) => {
   return [
     {
-      name: (
-        <RadioLabel
-          title={t`Values from column`}
-          isSelected={sourceType === null}
-        />
-      ),
-      value: null,
-    },
-    {
-      name: (
-        <RadioLabel
-          title={t`Values from a model or question`}
-          isSelected={sourceType === "card"}
-          onEditClick={() => onEdit("card")}
-        />
-      ),
-      value: "card",
-    },
-    {
-      name: (
-        <RadioLabel
-          title={t`Custom list`}
-          isSelected={sourceType === "static-list"}
-          onEditClick={() => onEdit("static-list")}
-        />
-      ),
-      value: "static-list",
+      name: <RadioLabel title={t`Dropdown list`} onEditClick={onEditClick} />,
+      value: "list",
     },
   ];
 };
diff --git a/frontend/src/metabase/parameters/components/ParameterSourceSettings/ParameterSourceSettings.unit.spec.tsx b/frontend/src/metabase/parameters/components/ParameterSourceSettings/ParameterSourceSettings.unit.spec.tsx
deleted file mode 100644
index 63da33cb293e8c2ab5df223e840da6a4b98d5695..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/parameters/components/ParameterSourceSettings/ParameterSourceSettings.unit.spec.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import React from "react";
-import { screen } from "@testing-library/react";
-import userEvent from "@testing-library/user-event";
-import { renderWithProviders } from "__support__/ui";
-import { createMockUiParameter } from "metabase-lib/mocks";
-import ParameterSourceSettings, {
-  ParameterSourceSettingsProps,
-} from "./ParameterSourceSettings";
-
-describe("ParameterSourceSettings", () => {
-  it("should set the default source type", () => {
-    const props = getProps({
-      parameter: createMockUiParameter({
-        values_source_type: "static-list",
-      }),
-    });
-
-    renderWithProviders(<ParameterSourceSettings {...props} />);
-    userEvent.click(screen.getByText("Values from column"));
-
-    expect(props.onChangeSourceType).toHaveBeenCalledWith(null);
-  });
-
-  it("should set up the static list source via the modal", () => {
-    const props = getProps();
-
-    renderWithProviders(<ParameterSourceSettings {...props} />);
-    userEvent.click(screen.getByText("Custom list"));
-    userEvent.type(screen.getByRole("textbox"), "Gadget");
-    userEvent.click(screen.getByText("Done"));
-
-    expect(props.onChangeSourceType).toHaveBeenCalledWith("static-list");
-    expect(props.onChangeSourceConfig).toHaveBeenCalledWith({
-      values: ["Gadget"],
-    });
-  });
-
-  it("should edit the static list source via the modal", () => {
-    const props = getProps({
-      parameter: createMockUiParameter({
-        values_source_type: "static-list",
-        values_source_config: { values: ["Gadget"] },
-      }),
-    });
-
-    renderWithProviders(<ParameterSourceSettings {...props} />);
-    userEvent.click(screen.getByText("Edit"));
-    userEvent.clear(screen.getByRole("textbox"));
-    userEvent.type(screen.getByRole("textbox"), "Widget");
-    userEvent.click(screen.getByText("Done"));
-
-    expect(props.onChangeSourceType).toHaveBeenCalledWith("static-list");
-    expect(props.onChangeSourceConfig).toHaveBeenCalledWith({
-      values: ["Widget"],
-    });
-  });
-
-  it("should not change the source type if the modal was dismissed", () => {
-    const props = getProps();
-
-    renderWithProviders(<ParameterSourceSettings {...props} />);
-    userEvent.click(screen.getByText("Custom list"));
-    userEvent.click(screen.getByText("Cancel"));
-
-    expect(props.onChangeSourceType).not.toHaveBeenCalled();
-    expect(props.onChangeSourceConfig).not.toHaveBeenCalled();
-  });
-});
-
-const getProps = (
-  opts?: Partial<ParameterSourceSettingsProps>,
-): ParameterSourceSettingsProps => ({
-  parameter: createMockUiParameter(),
-  onChangeSourceType: jest.fn(),
-  onChangeSourceConfig: jest.fn(),
-  ...opts,
-});
diff --git a/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceCardModal.styled.tsx b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceCardModal.styled.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..d33ddd092495b84089643d33258892f00bb2a8bf
--- /dev/null
+++ b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceCardModal.styled.tsx
@@ -0,0 +1,15 @@
+import styled from "@emotion/styled";
+import { ModalBody } from "./ValuesSourceModal.styled";
+
+export const ModalBodyWithSearch = styled(ModalBody)`
+  display: flex;
+  flex-direction: column;
+`;
+
+export const SearchInputContainer = styled.div`
+  margin-bottom: 1rem;
+`;
+
+export const DataPickerContainer = styled.div`
+  overflow-y: auto;
+`;
diff --git a/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceCardModal.tsx b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceCardModal.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..3c4b7e493daec63b789f8364fac15f4595e11d91
--- /dev/null
+++ b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceCardModal.tsx
@@ -0,0 +1,206 @@
+import React, { ChangeEvent, useCallback, useEffect } from "react";
+import { connect } from "react-redux";
+import { t } from "ttag";
+import _ from "underscore";
+import Button from "metabase/core/components/Button";
+import Input from "metabase/core/components/Input";
+import ModalContent from "metabase/components/ModalContent";
+import DataPicker, {
+  DataPickerDataType,
+  DataPickerValue,
+  useDataPicker,
+  useDataPickerValue,
+} from "metabase/containers/DataPicker";
+import Questions from "metabase/entities/questions";
+import Collections from "metabase/entities/collections";
+import Tables from "metabase/entities/tables";
+import { getMetadata } from "metabase/selectors/metadata";
+import {
+  Card,
+  CardId,
+  Collection,
+  ValuesSourceConfig,
+} from "metabase-types/api";
+import { State } from "metabase-types/store";
+import Question from "metabase-lib/Question";
+import {
+  getCollectionVirtualSchemaId,
+  getQuestionIdFromVirtualTableId,
+  getQuestionVirtualTableId,
+} from "metabase-lib/metadata/utils/saved-questions";
+import {
+  DataPickerContainer,
+  ModalBodyWithSearch,
+  SearchInputContainer,
+} from "./ValuesSourceCardModal.styled";
+
+const DATA_PICKER_FILTERS = {
+  types: (type: DataPickerDataType) =>
+    type === "questions" || type === "models",
+};
+
+interface ModalOwnProps {
+  name: string;
+  sourceConfig: ValuesSourceConfig;
+  onChangeSourceConfig: (sourceConfig: ValuesSourceConfig) => void;
+  onSubmit: () => void;
+  onClose: () => void;
+}
+
+interface ModalCardProps {
+  card: Card | undefined;
+}
+
+interface ModalCollectionProps {
+  collection: Collection | undefined;
+}
+
+interface ModalStateProps {
+  question: Question | undefined;
+}
+
+interface ModalDispatchProps {
+  onFetchCard: (cardId: CardId) => void;
+  onFetchMetadata: (cardId: CardId) => void;
+}
+
+type ModalProps = ModalOwnProps &
+  ModalCardProps &
+  ModalCollectionProps &
+  ModalStateProps &
+  ModalDispatchProps;
+
+const ValuesSourceCardModal = ({
+  name,
+  question,
+  collection,
+  onFetchCard,
+  onFetchMetadata,
+  onChangeSourceConfig,
+  onSubmit,
+  onClose,
+}: ModalProps): JSX.Element => {
+  const initialValue = getInitialValue(question, collection);
+  const [value, setValue] = useDataPickerValue(initialValue);
+  const cardId = getCardIdFromValue(value);
+
+  const handleSubmit = useCallback(() => {
+    onChangeSourceConfig({ card_id: cardId });
+    onSubmit();
+  }, [cardId, onChangeSourceConfig, onSubmit]);
+
+  useEffect(() => {
+    if (cardId) {
+      onFetchCard(cardId);
+      onFetchMetadata(cardId);
+    }
+  }, [cardId, onFetchCard, onFetchMetadata]);
+
+  return (
+    <DataPicker.Provider>
+      <ModalContent
+        title={t`Selectable values for ${name}`}
+        footer={[
+          <Button key="cancel" onClick={onSubmit}>{t`Back`}</Button>,
+          <Button
+            key="submit"
+            primary
+            disabled={!cardId}
+            onClick={handleSubmit}
+          >
+            {t`Done`}
+          </Button>,
+        ]}
+        onClose={onClose}
+      >
+        <ModalBodyWithSearch>
+          <DataPickerSearchInput />
+          <DataPickerContainer>
+            <DataPicker
+              value={value}
+              filters={DATA_PICKER_FILTERS}
+              onChange={setValue}
+            />
+          </DataPickerContainer>
+        </ModalBodyWithSearch>
+      </ModalContent>
+    </DataPicker.Provider>
+  );
+};
+
+const DataPickerSearchInput = () => {
+  const { search } = useDataPicker();
+  const { query, setQuery } = search;
+
+  const handleChange = useCallback(
+    (event: ChangeEvent<HTMLInputElement>) => {
+      setQuery(event.target.value);
+    },
+    [setQuery],
+  );
+
+  return (
+    <SearchInputContainer>
+      <Input
+        value={query}
+        placeholder={t`Search for a question or model`}
+        leftIcon="search"
+        fullWidth
+        onChange={handleChange}
+      />
+    </SearchInputContainer>
+  );
+};
+
+const getInitialValue = (
+  question?: Question,
+  collection?: Collection,
+): Partial<DataPickerValue> | undefined => {
+  if (question) {
+    const id = question.id();
+    const isDatasets = question.isDataset();
+
+    return {
+      type: isDatasets ? "models" : "questions",
+      schemaId: getCollectionVirtualSchemaId(collection, { isDatasets }),
+      collectionId: collection?.id,
+      tableIds: [getQuestionVirtualTableId(id)],
+    };
+  }
+};
+
+const getCardIdFromValue = ({ tableIds }: DataPickerValue) => {
+  if (tableIds.length) {
+    const cardId = getQuestionIdFromVirtualTableId(tableIds[0]);
+    if (cardId != null) {
+      return cardId;
+    }
+  }
+};
+
+const mapStateToProps = (
+  state: State,
+  { card }: ModalCardProps,
+): ModalStateProps => ({
+  question: card ? new Question(card, getMetadata(state)) : undefined,
+});
+
+const mapDispatchToProps: ModalDispatchProps = {
+  onFetchCard: (cardId: CardId) => Questions.actions.fetch({ id: cardId }),
+  onFetchMetadata: (cardId: CardId) =>
+    Tables.actions.fetchMetadata({ id: getQuestionVirtualTableId(cardId) }),
+};
+
+export default _.compose(
+  Questions.load({
+    id: (state: State, { sourceConfig: { card_id } }: ModalOwnProps) => card_id,
+    entityAlias: "card",
+    loadingAndErrorWrapper: false,
+  }),
+  Collections.load({
+    id: (state: State, { card }: ModalCardProps) =>
+      card?.collection_id ?? "root",
+    loadingAndErrorWrapper: false,
+  }),
+  connect(mapStateToProps, mapDispatchToProps),
+)(ValuesSourceCardModal);
diff --git a/frontend/src/metabase/parameters/components/CardValuesSourceModal/FieldStepModal.styled.tsx b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceModal.styled.tsx
similarity index 82%
rename from frontend/src/metabase/parameters/components/CardValuesSourceModal/FieldStepModal.styled.tsx
rename to frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceModal.styled.tsx
index aa97a2f3d6e4650847c683ac6f57079026c52ae3..094a8c3c2aacb80b161579e9a04aa8740c385340 100644
--- a/frontend/src/metabase/parameters/components/CardValuesSourceModal/FieldStepModal.styled.tsx
+++ b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceModal.styled.tsx
@@ -2,5 +2,4 @@ import styled from "@emotion/styled";
 
 export const ModalBody = styled.div`
   height: 50vh;
-  overflow-y: auto;
 `;
diff --git a/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceModal.tsx b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceModal.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..7c8a8c69ff5fd33ebb404a36a56028df8cbca245
--- /dev/null
+++ b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceModal.tsx
@@ -0,0 +1,69 @@
+import React, { useCallback, useMemo, useState } from "react";
+import { ValuesSourceConfig, ValuesSourceType } from "metabase-types/api";
+import { getNonVirtualFields } from "metabase-lib/parameters/utils/parameter-fields";
+import { UiParameter } from "metabase-lib/parameters/types";
+import { getSourceConfig, getSourceType } from "../../utils/dashboards";
+import ValuesSourceTypeModal from "./ValuesSourceTypeModal";
+import ValuesSourceCardModal from "./ValuesSourceCardModal";
+
+type ModalStep = "main" | "card";
+
+interface ModalProps {
+  parameter: UiParameter;
+  onSubmit: (
+    sourceType: ValuesSourceType,
+    sourceConfig: ValuesSourceConfig,
+  ) => void;
+  onClose: () => void;
+}
+
+const ValuesSourceModal = ({
+  parameter,
+  onSubmit,
+  onClose,
+}: ModalProps): JSX.Element => {
+  const [step, setStep] = useState<ModalStep>("main");
+  const [sourceType, setSourceType] = useState(getSourceType(parameter));
+  const [sourceConfig, setSourceConfig] = useState(getSourceConfig(parameter));
+
+  const fields = useMemo(() => {
+    return getNonVirtualFields(parameter);
+  }, [parameter]);
+
+  const handlePickerOpen = useCallback(() => {
+    setStep("card");
+  }, []);
+
+  const handlePickerClose = useCallback(() => {
+    setStep("main");
+  }, []);
+
+  const handleSubmit = useCallback(() => {
+    onSubmit(sourceType, sourceConfig);
+    onClose();
+  }, [sourceType, sourceConfig, onSubmit, onClose]);
+
+  return step === "main" ? (
+    <ValuesSourceTypeModal
+      name={parameter.name}
+      fields={fields}
+      sourceType={sourceType}
+      sourceConfig={sourceConfig}
+      onChangeSourceType={setSourceType}
+      onChangeSourceConfig={setSourceConfig}
+      onChangeCard={handlePickerOpen}
+      onSubmit={handleSubmit}
+      onClose={onClose}
+    />
+  ) : (
+    <ValuesSourceCardModal
+      name={parameter.name}
+      sourceConfig={sourceConfig}
+      onChangeSourceConfig={setSourceConfig}
+      onSubmit={handlePickerClose}
+      onClose={onClose}
+    />
+  );
+};
+
+export default ValuesSourceModal;
diff --git a/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceTypeModal.styled.tsx b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceTypeModal.styled.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..5dcbb135163bba9a300588a50111533f30d403fa
--- /dev/null
+++ b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceTypeModal.styled.tsx
@@ -0,0 +1,64 @@
+import styled from "@emotion/styled";
+import { color } from "metabase/lib/colors";
+import TextArea from "metabase/core/components/TextArea";
+import LoadingAndErrorWrapper from "metabase/components/LoadingAndErrorWrapper";
+import { ModalBody } from "metabase/parameters/components/ValuesSourceModal/ValuesSourceModal.styled";
+
+export const ModalBodyWithPane = styled(ModalBody)`
+  display: flex;
+  gap: 2rem;
+`;
+
+export const ModalPane = styled.div`
+  flex: 1;
+`;
+
+export const ModalMain = styled.div`
+  display: flex;
+  flex: 2;
+  flex-direction: row;
+`;
+
+export const ModalSection = styled.div`
+  margin-bottom: 1rem;
+`;
+
+export const ModalLabel = styled.label`
+  display: block;
+  color: ${color("text-medium")};
+  margin-bottom: 0.5rem;
+  font-weight: bold;
+`;
+
+export const ModalTextArea = styled(TextArea)`
+  display: block;
+  resize: none;
+`;
+
+export const ModalHelpMessage = styled.div`
+  color: ${color("text-medium")};
+  margin-top: 0.25rem;
+  margin-left: 1.25rem;
+`;
+
+export const ModalErrorMessage = styled.div`
+  color: ${color("text-medium")};
+  padding: 1rem;
+  border: 1px solid ${color("error")};
+  border-radius: 0.5rem;
+`;
+
+export const ModalEmptyState = styled.div`
+  display: flex;
+  flex: 1;
+  justify-content: center;
+  align-items: center;
+  padding: 2rem;
+  border: 1px solid ${color("border")};
+  border-radius: 0.5rem;
+  background-color: ${color("bg-light")};
+  color: ${color("text-medium")};
+  font-weight: bold;
+  line-height: 1.5rem;
+  text-align: center;
+`;
diff --git a/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceTypeModal.tsx b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceTypeModal.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..92fe7333bd794baff7984f0008d2a859b5e5ffa8
--- /dev/null
+++ b/frontend/src/metabase/parameters/components/ValuesSourceModal/ValuesSourceTypeModal.tsx
@@ -0,0 +1,411 @@
+import React, { ChangeEvent, useCallback, useEffect, useMemo } from "react";
+import { connect } from "react-redux";
+import { t } from "ttag";
+import _ from "underscore";
+import Button from "metabase/core/components/Button";
+import Radio from "metabase/core/components/Radio";
+import Select, {
+  Option,
+  SelectChangeEvent,
+} from "metabase/core/components/Select";
+import SelectButton from "metabase/core/components/SelectButton";
+import ModalContent from "metabase/components/ModalContent";
+import Collections from "metabase/entities/collections";
+import Fields from "metabase/entities/fields";
+import Tables from "metabase/entities/tables";
+import Questions from "metabase/entities/questions";
+import { getMetadata } from "metabase/selectors/metadata";
+import { Card, ValuesSourceConfig, ValuesSourceType } from "metabase-types/api";
+import { Dispatch, State } from "metabase-types/store";
+import Question from "metabase-lib/Question";
+import Field from "metabase-lib/metadata/Field";
+import { getQuestionVirtualTableId } from "metabase-lib/metadata/utils/saved-questions";
+import {
+  getDefaultSourceConfig,
+  isValidSourceConfig,
+} from "metabase-lib/parameters/utils/parameter-source";
+import {
+  ModalHelpMessage,
+  ModalLabel,
+  ModalBodyWithPane,
+  ModalMain,
+  ModalPane,
+  ModalSection,
+  ModalTextArea,
+  ModalErrorMessage,
+  ModalEmptyState,
+} from "./ValuesSourceTypeModal.styled";
+
+const NEW_LINE = "\n";
+
+const SOURCE_TYPE_OPTIONS = [
+  { name: t`From connected fields`, value: null },
+  { name: t`From another model or question`, value: "card" },
+  { name: t`Custom list`, value: "static-list" },
+];
+
+interface ModalOwnProps {
+  name: string;
+  fields: Field[];
+  sourceType: ValuesSourceType;
+  sourceConfig: ValuesSourceConfig;
+  onChangeSourceType: (sourceType: ValuesSourceType) => void;
+  onChangeSourceConfig: (sourceConfig: ValuesSourceConfig) => void;
+  onChangeCard: () => void;
+  onSubmit: () => void;
+  onClose: () => void;
+}
+
+interface ModalCardProps {
+  card: Card | undefined;
+}
+
+interface ModalStateProps {
+  question: Question | undefined;
+  fieldValues: string[][][];
+  isLoadingFieldValues: boolean;
+}
+
+interface ModalDispatchProps {
+  onFetchFieldValues: (fields: Field[]) => void;
+}
+
+type ModalProps = ModalOwnProps &
+  ModalCardProps &
+  ModalStateProps &
+  ModalDispatchProps;
+
+const ValuesSourceTypeModal = ({
+  name,
+  fields,
+  fieldValues,
+  isLoadingFieldValues,
+  question,
+  sourceType,
+  sourceConfig,
+  onFetchFieldValues,
+  onChangeSourceType,
+  onChangeSourceConfig,
+  onChangeCard,
+  onSubmit,
+  onClose,
+}: ModalProps): JSX.Element => {
+  const allFieldValues = useMemo(() => {
+    return getUniqueFieldValues(fieldValues);
+  }, [fieldValues]);
+
+  const handleTypeChange = useCallback(
+    (sourceType: ValuesSourceType) => {
+      onChangeSourceType(sourceType);
+      onChangeSourceConfig(getDefaultSourceConfig(sourceType, allFieldValues));
+    },
+    [allFieldValues, onChangeSourceType, onChangeSourceConfig],
+  );
+
+  useEffect(() => {
+    onFetchFieldValues(fields);
+  }, [fields, onFetchFieldValues]);
+
+  return (
+    <ModalContent
+      title={t`Selectable values for ${name}`}
+      footer={[
+        <Button
+          key="submit"
+          primary
+          disabled={!isValidSourceConfig(sourceType, sourceConfig)}
+          onClick={onSubmit}
+        >{t`Done`}</Button>,
+      ]}
+      onClose={onClose}
+    >
+      {sourceType === null ? (
+        <FieldSourceModal
+          fields={fields}
+          fieldValues={allFieldValues}
+          isLoadingFieldValues={isLoadingFieldValues}
+          sourceType={sourceType}
+          onChangeSourceType={handleTypeChange}
+        />
+      ) : sourceType === "card" ? (
+        <CardSourceModal
+          question={question}
+          sourceType={sourceType}
+          sourceConfig={sourceConfig}
+          onChangeCard={onChangeCard}
+          onChangeSourceType={handleTypeChange}
+          onChangeSourceConfig={onChangeSourceConfig}
+        />
+      ) : sourceType === "static-list" ? (
+        <ListSourceModal
+          sourceType={sourceType}
+          sourceConfig={sourceConfig}
+          fieldValues={allFieldValues}
+          onChangeSourceType={handleTypeChange}
+          onChangeSourceConfig={onChangeSourceConfig}
+        />
+      ) : null}
+    </ModalContent>
+  );
+};
+
+interface FieldSourceModalProps {
+  fields: Field[];
+  fieldValues: string[];
+  isLoadingFieldValues: boolean;
+  sourceType: ValuesSourceType;
+  onChangeSourceType: (sourceType: ValuesSourceType) => void;
+}
+
+const FieldSourceModal = ({
+  fields,
+  fieldValues,
+  isLoadingFieldValues,
+  sourceType,
+  onChangeSourceType,
+}: FieldSourceModalProps) => {
+  const hasFields = fields.length > 0;
+  const hasFieldValues = fieldValues.length > 0;
+
+  const fieldValuesText = useMemo(() => {
+    return getValuesText(fieldValues);
+  }, [fieldValues]);
+
+  return (
+    <ModalBodyWithPane>
+      <ModalPane>
+        <ModalSection>
+          <ModalLabel>{t`Where values should come from`}</ModalLabel>
+          <Radio
+            value={sourceType}
+            options={SOURCE_TYPE_OPTIONS}
+            vertical
+            onChange={onChangeSourceType}
+          />
+        </ModalSection>
+      </ModalPane>
+      <ModalMain>
+        {!hasFields ? (
+          <ModalEmptyState>
+            {t`You haven’t connected a field to this filter yet, so there aren’t any values.`}
+          </ModalEmptyState>
+        ) : !hasFieldValues && !isLoadingFieldValues ? (
+          <ModalEmptyState>
+            {t`We don’t have any cached values for the connected fields. Try one of the other options, or change this widget to a search box.`}
+          </ModalEmptyState>
+        ) : (
+          <ModalTextArea value={fieldValuesText} readOnly fullWidth />
+        )}
+      </ModalMain>
+    </ModalBodyWithPane>
+  );
+};
+
+interface CardSourceModalProps {
+  question: Question | undefined;
+  sourceType: ValuesSourceType;
+  sourceConfig: ValuesSourceConfig;
+  onChangeCard: () => void;
+  onChangeSourceType: (sourceType: ValuesSourceType) => void;
+  onChangeSourceConfig: (sourceConfig: ValuesSourceConfig) => void;
+}
+
+const CardSourceModal = ({
+  question,
+  sourceType,
+  sourceConfig,
+  onChangeCard,
+  onChangeSourceType,
+  onChangeSourceConfig,
+}: CardSourceModalProps) => {
+  const fields = useMemo(() => {
+    return question ? getSupportedFields(question) : [];
+  }, [question]);
+
+  const selectedField = useMemo(() => {
+    return getFieldByReference(fields, sourceConfig.value_field);
+  }, [fields, sourceConfig]);
+
+  const handleFieldChange = useCallback(
+    (event: SelectChangeEvent<Field>) => {
+      onChangeSourceConfig({
+        ...sourceConfig,
+        value_field: event.target.value.reference(),
+      });
+    },
+    [sourceConfig, onChangeSourceConfig],
+  );
+
+  return (
+    <ModalBodyWithPane>
+      <ModalPane>
+        <ModalSection>
+          <ModalLabel>{t`Where values should come from`}</ModalLabel>
+          <Radio
+            value={sourceType}
+            options={SOURCE_TYPE_OPTIONS}
+            vertical
+            onChange={onChangeSourceType}
+          />
+        </ModalSection>
+        <ModalSection>
+          <ModalLabel>{t`Model or question to supply the values`}</ModalLabel>
+          <SelectButton onClick={onChangeCard}>
+            {question ? question.displayName() : t`Pick a model or question…`}
+          </SelectButton>
+        </ModalSection>
+        {question && (
+          <ModalSection>
+            <ModalLabel>{t`Column to supply the values`}</ModalLabel>
+            {fields.length ? (
+              <Select
+                value={selectedField}
+                placeholder={t`Pick a column…`}
+                onChange={handleFieldChange}
+              >
+                {fields.map((field, index) => (
+                  <Option
+                    key={index}
+                    name={field.displayName()}
+                    value={field}
+                  />
+                ))}
+              </Select>
+            ) : (
+              <ModalErrorMessage>
+                {question.isDataset()
+                  ? t`This model doesn’t have any text columns.`
+                  : t`This question doesn’t have any text columns.`}{" "}
+                {t`Please pick a different model or question.`}
+              </ModalErrorMessage>
+            )}
+          </ModalSection>
+        )}
+      </ModalPane>
+      <ModalMain>
+        {!question ? (
+          <ModalEmptyState>{t`Pick a model or question`}</ModalEmptyState>
+        ) : !selectedField ? (
+          <ModalEmptyState>{t`Pick a column`}</ModalEmptyState>
+        ) : (
+          <ModalTextArea readOnly fullWidth />
+        )}
+      </ModalMain>
+    </ModalBodyWithPane>
+  );
+};
+
+interface ListSourceModalProps {
+  sourceType: ValuesSourceType;
+  sourceConfig: ValuesSourceConfig;
+  fieldValues: string[];
+  onChangeSourceType: (sourceType: ValuesSourceType) => void;
+  onChangeSourceConfig: (sourceConfig: ValuesSourceConfig) => void;
+}
+
+const ListSourceModal = ({
+  sourceType,
+  sourceConfig,
+  onChangeSourceType,
+  onChangeSourceConfig,
+}: ListSourceModalProps) => {
+  const handleValuesChange = useCallback(
+    (event: ChangeEvent<HTMLTextAreaElement>) => {
+      onChangeSourceConfig({ values: getStaticValues(event.target.value) });
+    },
+    [onChangeSourceConfig],
+  );
+
+  return (
+    <ModalBodyWithPane>
+      <ModalPane>
+        <ModalSection>
+          <ModalLabel>{t`Where values should come from`}</ModalLabel>
+          <Radio
+            value={sourceType}
+            options={SOURCE_TYPE_OPTIONS}
+            vertical
+            onChange={onChangeSourceType}
+          />
+          <ModalHelpMessage>{t`Enter one value per line.`}</ModalHelpMessage>
+        </ModalSection>
+      </ModalPane>
+      <ModalMain>
+        <ModalTextArea
+          defaultValue={getValuesText(sourceConfig.values)}
+          fullWidth
+          onChange={handleValuesChange}
+        />
+      </ModalMain>
+    </ModalBodyWithPane>
+  );
+};
+
+const getValuesText = (values?: string[]) => {
+  return values?.join(NEW_LINE) ?? "";
+};
+
+const getUniqueFieldValues = (fieldsValues: string[][][]) => {
+  const allValues = fieldsValues.flatMap(values => values.map(([key]) => key));
+  return Array.from(new Set(allValues));
+};
+
+const getStaticValues = (value: string) => {
+  return value
+    .split(NEW_LINE)
+    .map(line => line.trim())
+    .filter(line => line.length > 0);
+};
+
+const getFieldByReference = (fields: Field[], fieldReference?: unknown[]) => {
+  return fields.find(field => _.isEqual(field.reference(), fieldReference));
+};
+
+const getSupportedFields = (question: Question) => {
+  const fields = question.composeThisQuery()?.table()?.fields ?? [];
+  return fields.filter(field => field.isString());
+};
+
+const mapStateToProps = (
+  state: State,
+  { card, fields }: ModalOwnProps & ModalCardProps,
+): ModalStateProps => ({
+  question: card ? new Question(card, getMetadata(state)) : undefined,
+  fieldValues: fields.map(field =>
+    Fields.selectors.getFieldValues(state, { entityId: field.id }),
+  ),
+  isLoadingFieldValues: fields.every(field =>
+    Fields.selectors.getLoading(state, {
+      entityId: field.id,
+      requestType: "values",
+    }),
+  ),
+});
+
+const mapDispatchToProps = (dispatch: Dispatch): ModalDispatchProps => ({
+  onFetchFieldValues: (fields: Field[]) => {
+    fields.forEach(field =>
+      dispatch(Fields.actions.fetchFieldValues({ id: field.id })),
+    );
+  },
+});
+
+export default _.compose(
+  Tables.load({
+    id: (state: State, { sourceConfig: { card_id } }: ModalOwnProps) =>
+      card_id ? getQuestionVirtualTableId(card_id) : undefined,
+    requestType: "fetchMetadata",
+    loadingAndErrorWrapper: false,
+  }),
+  Questions.load({
+    id: (state: State, { sourceConfig: { card_id } }: ModalOwnProps) => card_id,
+    entityAlias: "card",
+    loadingAndErrorWrapper: false,
+  }),
+  Collections.load({
+    id: (state: State, { card }: ModalCardProps) =>
+      card?.collection_id ?? "root",
+    loadingAndErrorWrapper: false,
+  }),
+  connect(mapStateToProps, mapDispatchToProps),
+)(ValuesSourceTypeModal);
diff --git a/frontend/src/metabase/parameters/components/ValuesSourceModal/index.ts b/frontend/src/metabase/parameters/components/ValuesSourceModal/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..92f817d3a3f40b98ac61ef86fd02c9cf520bf5b5
--- /dev/null
+++ b/frontend/src/metabase/parameters/components/ValuesSourceModal/index.ts
@@ -0,0 +1 @@
+export { default } from "./ValuesSourceModal";
diff --git a/frontend/test/metabase/scenarios/dashboard-filters/dashboard-filters-source.cy.spec.js b/frontend/test/metabase/scenarios/dashboard-filters/dashboard-filters-source.cy.spec.js
index 05fb76e0570d3c4c336a24a25e414ec868b6549b..499f9a9c8bddf3b23025a62c4e66e3d4df658f05 100644
--- a/frontend/test/metabase/scenarios/dashboard-filters/dashboard-filters-source.cy.spec.js
+++ b/frontend/test/metabase/scenarios/dashboard-filters/dashboard-filters-source.cy.spec.js
@@ -53,8 +53,9 @@ describe("scenarios > dashboard > filters", () => {
 
     editDashboard();
     setFilter("Text or Category", "Dropdown");
-    setupStructuredQuestionSource();
     mapFilterToQuestion();
+    editDropdown();
+    setupStructuredQuestionSource();
     saveDashboard();
     filterDashboard();
   });
@@ -69,8 +70,9 @@ describe("scenarios > dashboard > filters", () => {
 
     editDashboard();
     setFilter("Text or Category", "Dropdown");
-    setupNativeQuestionSource();
     mapFilterToQuestion();
+    editDropdown();
+    setupNativeQuestionSource();
     saveDashboard();
     filterDashboard();
   });
@@ -84,53 +86,73 @@ describe("scenarios > dashboard > filters", () => {
 
     editDashboard();
     setFilter("Text or Category", "Dropdown");
-    setupCustomList();
     mapFilterToQuestion();
+    editDropdown();
+    setupCustomList();
     saveDashboard();
     filterDashboard();
   });
 });
 
+const editDropdown = () => {
+  cy.findByText("Dropdown list").click();
+  cy.findByText("Edit").click();
+};
+
 const setupStructuredQuestionSource = () => {
-  cy.findByText("Values from a model or question").click();
+  modal().within(() => {
+    cy.findByText("From another model or question").click();
+    cy.findByText("Pick a model or question…").click();
+  });
+
   modal().within(() => {
     cy.findByPlaceholderText(/Search for a question/).type("Categories");
     cy.findByText("Categories").click();
-    cy.button("Select column").click();
+    cy.button("Done").click();
   });
+
   modal().within(() => {
-    cy.findByText("Pick a column").click();
+    cy.findByText("Pick a column…").click();
   });
+
   popover().within(() => {
     cy.findByText("Category").click();
   });
+
   modal().within(() => {
     cy.button("Done").click();
   });
 };
 
 const setupNativeQuestionSource = () => {
-  cy.findByText("Values from a model or question").click();
   modal().within(() => {
-    cy.findByText("Saved Questions").click();
+    cy.findByText("From another model or question").click();
+    cy.findByText("Pick a model or question…").click();
+  });
+
+  modal().within(() => {
     cy.findByText("Categories").click();
-    cy.button("Select column").click();
+    cy.button("Done").click();
   });
+
   modal().within(() => {
-    cy.findByText("Pick a column").click();
+    cy.findByText("Pick a column…").click();
   });
+
   popover().within(() => {
     cy.findByText("CATEGORY").click();
   });
+
   modal().within(() => {
     cy.button("Done").click();
   });
 };
 
 const setupCustomList = () => {
-  cy.findByText("Custom list").click();
   modal().within(() => {
-    cy.findByPlaceholderText(/banana/).type("Doohickey\nGadget");
+    cy.findByText("Custom list").click();
+    cy.findByRole("textbox").should("contain.value", "Gizmo");
+    cy.findByRole("textbox").clear().type("Doohickey\nGadget");
     cy.button("Done").click();
   });
 };
@@ -142,6 +164,7 @@ const mapFilterToQuestion = () => {
 
 const filterDashboard = () => {
   cy.findByText("Text").click();
+
   popover().within(() => {
     cy.findByText("Doohickey").should("be.visible");
     cy.findByText("Gadget").should("be.visible");
@@ -151,6 +174,6 @@ const filterDashboard = () => {
     cy.findByText("Doohickey").should("not.exist");
     cy.findByText("Gadget").click();
     cy.button("Add filter").click();
+    cy.wait("@getCardQuery");
   });
-  cy.wait("@getCardQuery");
 };