diff --git a/openbis_ng_ui/package.json b/openbis_ng_ui/package.json
index 41eb6a858624e65777bc677bf9dbeae70d4140e0..91916e3b1acb7a67703a0fa7cd6a9f04b04bbe06 100644
--- a/openbis_ng_ui/package.json
+++ b/openbis_ng_ui/package.json
@@ -12,12 +12,15 @@
     "install": "^0.13.0",
     "npm": "^6.14.8",
     "path-to-regexp": "^6.1.0",
+    "prism-themes": "^1.5.0",
+    "prismjs": "^1.22.0",
     "prop-types": "^15.7.2",
     "re-resizable": "^6.5.4",
     "react": "^16.13.1",
     "react-beautiful-dnd": "^13.0.0",
     "react-dom": "^16.13.1",
     "react-redux": "^7.2.1",
+    "react-simple-code-editor": "^0.11.0",
     "redux": "^4.0.5",
     "redux-saga": "^1.1.3",
     "reselect": "^4.0.0",
diff --git a/openbis_ng_ui/src/js/components/common/form/SourceCodeField.jsx b/openbis_ng_ui/src/js/components/common/form/SourceCodeField.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..dd59f4e897922046ea33f21ed12f4494d9a0f68a
--- /dev/null
+++ b/openbis_ng_ui/src/js/components/common/form/SourceCodeField.jsx
@@ -0,0 +1,135 @@
+import _ from 'lodash'
+import React from 'react'
+import autoBind from 'auto-bind'
+import { withStyles, withTheme } from '@material-ui/core/styles'
+import { highlight, languages } from 'prismjs/components/prism-core.js'
+import 'prismjs/components/prism-clike.js'
+import 'prismjs/components/prism-python.js'
+import 'prismjs/themes/prism.css'
+import Editor from 'react-simple-code-editor'
+import FormFieldContainer from '@src/js/components/common/form/FormFieldContainer.jsx'
+import logger from '@src/js/common/logger.js'
+
+const styles = theme => ({
+  view: {
+    fontFamily: theme.typography.sourceCode.fontFamily,
+    fontSize: theme.typography.body2.fontSize,
+    whiteSpace: 'pre-wrap',
+    padding: theme.spacing(2),
+    border: `1px solid ${theme.palette.border.secondary}`
+  },
+
+  edit: {
+    backgroundColor: theme.palette.background.field,
+    '& *': {
+      background: 'none !important'
+    },
+    '& textarea': {
+      border: `1px solid ${theme.palette.border.primary} !important`,
+      borderBottom: `1px solid ${theme.palette.border.field} !important`,
+      outline: 'none !important'
+    },
+    '& textarea:focus': {
+      borderBottom: `2px solid ${theme.palette.primary.main} !important`
+    }
+  },
+  error: {
+    '&$edit textarea': {
+      borderBottom: `2px solid ${theme.palette.error.main} !important`
+    }
+  },
+  disabled: {
+    '&$edit pre': {
+      opacity: 0.5
+    }
+  }
+})
+
+class SourceCodeField extends React.PureComponent {
+  constructor(props) {
+    super(props)
+    autoBind(this)
+  }
+
+  handleValueChange(value) {
+    const { name, onChange } = this.props
+    if (onChange) {
+      onChange({
+        target: {
+          name,
+          value
+        }
+      })
+    }
+  }
+
+  render() {
+    logger.log(logger.DEBUG, 'SourceCodeField.render')
+
+    const { mode } = this.props
+
+    if (mode === 'view') {
+      return this.renderView()
+    } else if (mode === 'edit') {
+      return this.renderEdit()
+    } else {
+      throw 'Unsupported mode: ' + mode
+    }
+  }
+
+  renderView() {
+    const { value, classes } = this.props
+    const html = { __html: highlight(value || '', languages.python) }
+
+    return <div className={classes.view} dangerouslySetInnerHTML={html} />
+  }
+
+  renderEdit() {
+    const {
+      name,
+      value,
+      description,
+      disabled,
+      error,
+      onClick,
+      onFocus,
+      onBlur,
+      theme,
+      styles,
+      classes
+    } = this.props
+    return (
+      <FormFieldContainer
+        description={description}
+        error={error}
+        styles={styles}
+        onClick={onClick}
+      >
+        <div
+          className={`
+            ${classes.edit} 
+            ${error ? classes.error : ''} 
+            ${disabled ? classes.disabled : ''}
+          `}
+        >
+          <Editor
+            name={name}
+            value={value || ''}
+            highlight={code => highlight(code, languages.python)}
+            disabled={disabled}
+            padding={this.props.theme.spacing(2)}
+            style={{
+              fontFamily: theme.typography.sourceCode.fontFamily,
+              fontSize: this.props.theme.typography.body2.fontSize
+            }}
+            onValueChange={this.handleValueChange}
+            onFocus={onFocus}
+            onBlur={onBlur}
+          />
+        </div>
+      </FormFieldContainer>
+    )
+  }
+}
+
+export default _.flow(withStyles(styles), withTheme)(SourceCodeField)
diff --git a/openbis_ng_ui/src/js/components/common/theme/ThemeProvider.jsx b/openbis_ng_ui/src/js/components/common/theme/ThemeProvider.jsx
index f67e2f45d72f35a08890e3486b9b5b7c3bc1643f..2088b09777b35f5d27fab0d066a8e3eb5af4e489 100644
--- a/openbis_ng_ui/src/js/components/common/theme/ThemeProvider.jsx
+++ b/openbis_ng_ui/src/js/components/common/theme/ThemeProvider.jsx
@@ -9,6 +9,9 @@ const config = {
     label: {
       fontSize: '0.7rem',
       color: '#0000008a'
+    },
+    sourceCode: {
+      fontFamily: '"Fira code", "Fira Mono", monospace'
     }
   },
   palette: {
@@ -29,11 +32,13 @@ const config = {
     },
     background: {
       primary: '#ebebeb',
-      secondary: '#f5f5f5'
+      secondary: '#f5f5f5',
+      field: '#e8e8e8'
     },
     border: {
       primary: '#dbdbdb',
-      secondary: '#ebebeb'
+      secondary: '#ebebeb',
+      field: '#878787'
     }
   }
 }
diff --git a/openbis_ng_ui/src/js/components/tools/form/plugin/PluginFormScript.jsx b/openbis_ng_ui/src/js/components/tools/form/plugin/PluginFormScript.jsx
index 2536a6095ac2f7d7e157c4cdf8a782d2ca59e814..b586abcfd2d9e14d24d4fb7f164d4f3e9dd1cb3c 100644
--- a/openbis_ng_ui/src/js/components/tools/form/plugin/PluginFormScript.jsx
+++ b/openbis_ng_ui/src/js/components/tools/form/plugin/PluginFormScript.jsx
@@ -2,7 +2,7 @@ import React from 'react'
 import { withStyles } from '@material-ui/core/styles'
 import Container from '@src/js/components/common/form/Container.jsx'
 import Header from '@src/js/components/common/form/Header.jsx'
-import TextField from '@src/js/components/common/form/TextField.jsx'
+import SourceCodeField from '@src/js/components/common/form/SourceCodeField.jsx'
 import PluginFormSelectionType from '@src/js/components/tools/form/plugin/PluginFormSelectionType.js'
 import logger from '@src/js/common/logger.js'
 
@@ -85,12 +85,11 @@ class PluginFormScript extends React.PureComponent {
     const { mode, classes } = this.props
     return (
       <div className={classes.field}>
-        <TextField
+        <SourceCodeField
           reference={this.references.script}
           label='Script'
           name='script'
           mandatory={true}
-          multiline={true}
           error={error}
           disabled={!enabled}
           value={value}