diff --git a/src/apps/state-docs/pd-to-md.ts b/src/apps/state-docs/pd-to-md.ts
index 310962f40f1f96d053db19466506e87595dfc8da..fb31b2ce3f07807c2639ea620dce1100bfc3fb1f 100644
--- a/src/apps/state-docs/pd-to-md.ts
+++ b/src/apps/state-docs/pd-to-md.ts
@@ -28,6 +28,7 @@ function paramInfo(param: PD.Any, offset: number): string {
         case 'group': return `Object with:\n${getParams(param.params, offset + 2)}`;
         case 'mapped': return `Object { name: string, params: object } where name+params are:\n${getMapped(param, offset + 2)}`;
         case 'line-graph': return `A list of 2d vectors [xi, yi][]`;
+        case 'list': return `Array of\n${paramInfo(param.element, offset + 2)}`;
         // TODO: support more languages
         case 'script-expression': return `An expression in the specified language { language: 'mol-script', expressiong: string }`;
         default:
diff --git a/src/mol-plugin/ui/controls/parameters.tsx b/src/mol-plugin/ui/controls/parameters.tsx
index c09203ccdf7e27ca81bbe27594b0ac10518e95cb..27a87940ad9acfd302c06decfdfa0e013437b97d 100644
--- a/src/mol-plugin/ui/controls/parameters.tsx
+++ b/src/mol-plugin/ui/controls/parameters.tsx
@@ -64,6 +64,7 @@ function controlFor(param: PD.Any): ParamControl | undefined {
         case 'mapped': return MappedControl;
         case 'line-graph': return LineGraphControl;
         case 'script-expression': return ScriptExpressionControl;
+        case 'list': return ListControl;
         default:
             const _: never = param;
             console.warn(`${_} has no associated UI component`);
@@ -511,6 +512,23 @@ export class MappedControl extends React.PureComponent<ParamProps<PD.Mapped<any>
     }
 }
 
+
+export class ListControl extends React.PureComponent<ParamProps<PD.List>, { isExpanded: boolean }> {
+    // state = { isExpanded: !!this.props.param.isExpanded }
+
+    // change(value: any) {
+    //     this.props.onChange({ name: this.props.name, param: this.props.param, value });
+    // }
+
+    // onChangeParam: ParamOnChange = e => {
+    //     this.change({ ...this.props.value, [e.name]: e.value });
+    // }
+
+    render() {
+        return <span>TODO</span>;
+    }
+}
+
 export class ConditionedControl extends React.PureComponent<ParamProps<PD.Conditioned<any, any, any>>> {
     change(value: PD.Conditioned<any, any, any>['defaultValue']) {
         this.props.onChange({ name: this.props.name, param: this.props.param, value });
diff --git a/src/mol-util/param-definition.ts b/src/mol-util/param-definition.ts
index 3bb4e3ed84140937872cf12da198e9c63ed3501f..a42b5b782b98e51de951a70a71e51ab5aa197e9b 100644
--- a/src/mol-util/param-definition.ts
+++ b/src/mol-util/param-definition.ts
@@ -189,6 +189,15 @@ export namespace ParamDefinition {
         }, info);
     }
 
+    export interface List<T = any> extends Base<T[]> {
+        type: 'list',
+        element: Any,
+        getLabel(t: T): string
+    }
+    export function List<T extends Any>(element: T, getLabel: (e: T['defaultValue']) => string, info?: Info & { defaultValue?: T['defaultValue'][] }): List<T['defaultValue']> {
+        return setInfo<List<T['defaultValue']>>({ type: 'list', element, getLabel, defaultValue: (info && info.defaultValue) || []  });
+    }
+
     export interface Converted<T, C> extends Base<T> {
         type: 'converted',
         converted: Any,
@@ -220,7 +229,9 @@ export namespace ParamDefinition {
         return setInfo<ScriptExpression>({ type: 'script-expression', defaultValue }, info)
     }
 
-    export type Any = Value<any> | Select<any> | MultiSelect<any> | Boolean | Text | Color | Vec3 | Numeric | FileParam | Interval | LineGraph | ColorScale<any> | Group<any> | Mapped<any> | Converted<any, any> | Conditioned<any, any, any> | ScriptExpression
+    export type Any =
+        | Value<any> | Select<any> | MultiSelect<any> | Boolean | Text | Color | Vec3 | Numeric | FileParam | Interval | LineGraph
+        | ColorScale<any> | Group<any> | Mapped<any> | Converted<any, any> | Conditioned<any, any, any> | ScriptExpression | List
 
     export type Params = { [k: string]: Any }
     export type Values<T extends Params> = { [k in keyof T]: T[k]['defaultValue'] }
@@ -311,6 +322,14 @@ export namespace ParamDefinition {
         } else if (p.type === 'script-expression') {
             const u = a as ScriptExpression['defaultValue'], v = b as ScriptExpression['defaultValue'];
             return u.language === v.language && u.expression === v.expression;
+        } else if (p.type === 'list') {
+            const u = a as List['defaultValue'], v = b as List['defaultValue'];
+            const l = u.length;
+            if (l !== v.length) return false;
+            for (let i = 0; i < l; i++) {
+                if (!isParamEqual(p.element, u[i], v[i])) return false;
+            }
+            return true;
         } else if (typeof a === 'object' && typeof b === 'object') {
             return shallowEqual(a, b);
         }