diff --git a/client/components/PaneMCQ.jsx b/client/components/PaneMCQ.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..c77b1cc47063620eb9255b186a229aabfb052617
--- /dev/null
+++ b/client/components/PaneMCQ.jsx
@@ -0,0 +1,146 @@
+import React from 'react'
+
+/**
+ * PanelMCQ is a component that allows the user to generate mcq options
+ */
+class PanelMCQ extends React.Component {
+  constructor (props) {
+    super(props)
+    this.onChangeNPA = this.onChangeNPA.bind(this)
+    this.onChangeLabelType = this.onChangeLabelType.bind(this)
+    this.generateLabels = this.generateLabels.bind(this)
+    this.state = {
+      chosenLabelType: 0,
+      nrPossibleAnswers: 2,
+      labelTypes: ['None', 'True/False', 'A, B, C ...', '1, 2, 3 ...']
+    }
+  }
+
+  // this function is called when the input is changed for the number of possible answers
+  onChangeNPA (e) {
+    let value = parseInt(e.target.value)
+    if (!isNaN(value)) {
+      if (this.state.chosenLabelType === 1) {
+        value = 2
+      }
+      this.setState({
+        nrPossibleAnswers: value
+      })
+    }
+  }
+
+  // this function is called when the input is changed for the desired label type
+  onChangeLabelType (e) {
+    let value = parseInt(e.target.value)
+    if (!isNaN(value)) {
+      this.setState({
+        chosenLabelType: value
+      })
+      if (parseInt(value) === 1) {
+        this.setState({
+          nrPossibleAnswers: 2
+        })
+      }
+    }
+  }
+
+  /**
+   * This function generates an array with the labels for each option
+   * @param nrLabels the number of options that need to be generated
+   * @returns {any[]|string[]|number[]}
+   */
+  generateLabels (nrLabels) {
+    let type = this.state.chosenLabelType
+
+    switch (type) {
+      case 1:
+        return ['T', 'F']
+      case 2:
+        return Array.from(Array(nrLabels).keys()).map((e) => String.fromCharCode(e + 65))
+      case 3:
+        return Array.from(Array(nrLabels).keys()).map(e => e + 1)
+      default:
+        return Array(nrLabels).fill(' ')
+    }
+  }
+
+  /**
+   * This function renders the panel with the inputs for generating multiple choice options
+   * @returns the react component containing the mcq panel
+   */
+  render () {
+    return (
+      <nav className='panel'>
+        <p className='panel-heading'>
+          Multiple Choice Question
+        </p>
+        <div className='panel-block'>
+          <div className='field'>
+            <React.Fragment>
+              <label className='label'>Number possible answers</label>
+              <div className='control'>
+                {(function () {
+                  var optionList = []
+                  for (var i = 1; i <= this.props.totalNrAnswers; i++) {
+                    const optionElement = <option key={i} value={String(i)}>{i}</option>
+                    optionList.push(optionElement)
+                  }
+                  return (<div className='select is-hovered is-fullwidth'>
+                    <select value={this.state.nrPossibleAnswers} onChange={this.onChangeNPA}>{optionList}</select>
+                  </div>)
+                }.bind(this)())}
+              </div>
+            </React.Fragment>
+          </div>
+        </div>
+        <div className='panel-block'>
+          <div className='field'>
+            <React.Fragment>
+              <label className='label'>Answer boxes labels</label>
+              <div className='control'>
+                <div className='select is-hovered is-fullwidth'>
+                  {(function () {
+                    var optionList = this.state.labelTypes.map(
+                      (label, i) => <option key={i} value={String(i)}>{label}</option>
+                    )
+                    return (
+                      <div className='select is-hovered is-fullwidth'>
+                        <select value={this.state.chosenLabelType} onChange={this.onChangeLabelType}>
+                          {optionList}
+                        </select>
+                      </div>
+                    )
+                  }.bind(this)())}
+                </div>
+              </div>
+            </React.Fragment>
+          </div>
+        </div>
+        <div className='panel-block field is-grouped'>
+          <button
+            disabled={this.props.disabledGenerateBoxes}
+            className='button is-link is-fullwidth'
+            onClick={() => {
+              let npa = this.state.nrPossibleAnswers
+              let labels = this.generateLabels(npa)
+              this.props.onGenerateBoxesClick(labels)
+            }}
+          >
+            Generate
+          </button>
+          <button
+            disabled={this.props.disabledDeleteBoxes}
+            className='button is-danger is-fullwidth'
+            onClick={() => {
+              this.props.onDeleteBoxesClick()
+            }}
+          >
+            Delete
+          </button>
+        </div>
+      </nav>
+    )
+  }
+}
+
+export default PanelMCQ
diff --git a/client/components/answer_box.png b/client/components/answer_box.png
new file mode 100644
index 0000000000000000000000000000000000000000..eafc3d30a9f99f21693f9075b9d446e43ce933fc
Binary files /dev/null and b/client/components/answer_box.png differ
diff --git a/client/views/Exam.css b/client/views/Exam.css
index f126f590b4b1ecb24c75893ea13582ced0d185a4..e70724da849022d617945ccebe204ea143ad9fea 100644
--- a/client/views/Exam.css
+++ b/client/views/Exam.css
@@ -1,3 +1,33 @@
+:root {
+    --option-width:20px;
+    --label-font-size:14px;
+}
+
+div.mcq-widget {
+    display:inline-flex;
+}
+
+div.mcq-option {
+    display: block;
+    width: var(--option-width);
+    padding:2px;
+    box-sizing: content-box;
+    height: auto;
+}
+
+div.mcq-option div.mcq-option-label {
+    display:block;
+    font-family: Arial, Helvetica, sans-serif;
+    font-size: var(--label-font-size);
+    text-align: center;
+}
+
+div.mcq-option img.mcq-box {
+    display: block;
+    margin:auto;
+}
+
+
 .editor-content {
   background-color: #ddd;
   border-radius: 10px
diff --git a/client/views/Exam.jsx b/client/views/Exam.jsx
index 60d0c33a5f54df9d4324b01e573898102bd32752..702b44a5cedddbbe008b53853981eac5d2531b50 100644
--- a/client/views/Exam.jsx
+++ b/client/views/Exam.jsx
@@ -6,6 +6,7 @@ import Hero from '../components/Hero.jsx'
 import './Exam.css'
 import GeneratedExamPreview from '../components/GeneratedExamPreview.jsx'
 import PanelGenerate from '../components/PanelGenerate.jsx'
+import PanelMCQ from '../components/PaneMCQ.jsx'
 import ExamEditor from './ExamEditor.jsx'
 import update from 'immutability-helper'
 import ExamFinalizeMarkdown from './ExamFinalize.md'
@@ -23,7 +24,9 @@ class Exams extends React.Component {
     widgets: [],
     previewing: false,
     deletingExam: false,
-    deletingWidget: false
+    deletingWidget: false,
+    deletingMCWidget: false,
+    showPanelMCQ: false
   }
 
   static getDerivedStateFromProps = (newProps, prevState) => {
@@ -38,7 +41,9 @@ class Exams extends React.Component {
             id: problem.id,
             page: problem.page,
             name: problem.name,
-            graded: problem.graded
+            graded: problem.graded,
+            mc_options: problem.mc_options,
+            isMCQ: problem.mc_options && problem.mc_options.length !== 0 // is the problem a mc question - used to display PanelMCQ
           }
         }
       })
@@ -100,6 +105,19 @@ class Exams extends React.Component {
       }))
   }
 
+  createNewWidget = (widgetData) => {
+    this.setState((prevState) => {
+      return {
+        selectedWidgetId: widgetData.id,
+        widgets: update(prevState.widgets, {
+          [widgetData.id]: {
+            $set: widgetData
+          }
+        })
+      }
+    })
+  }
+
   deleteWidget = (widgetId) => {
     const widget = this.state.widgets[widgetId]
     if (widget) {
@@ -164,17 +182,10 @@ class Exams extends React.Component {
               selectedWidgetId: widgetId
             })
           }}
-          createNewWidget={(widgetData) => {
-            this.setState((prevState) => {
-              return {
-                selectedWidgetId: widgetData.id,
-                widgets: update(prevState.widgets, {
-                  [widgetData.id]: {
-                    $set: widgetData
-                  }
-                })
-              }
-            })
+          createNewWidget={this.createNewWidget}
+          updateMCWidgetPosition={this.updateMCWidgetPosition}
+          updateExam={() => {
+            this.props.updateExam(this.props.examID)
           }}
         />
       )
@@ -234,6 +245,141 @@ class Exams extends React.Component {
     })
   }
 
+  /**
+   * This function deletes the mc options coupled to a problem.
+   */
+  deleteMCWidget = () => {
+    const widget = this.state.widgets[this.state.selectedWidgetId]
+    const options = widget.problem.mc_options
+    if (options.length > 0) {
+      options.forEach((option) => {
+        api.del('mult-choice/' + option.id)
+          .catch(err => {
+            console.log(err)
+            err.json().then(res => {
+              this.setState({
+                deletingMCWidget: false
+              })
+              Notification.error('Could not delete multiple choice option' +
+                (res.message ? ': ' + res.message : ''))
+              // update to try and get a consistent state
+              this.props.updateExam(this.props.examID)
+            })
+          })
+      })
+
+      // remove the mc options from the state
+      // note that his can happen before they are removed in the DB due to async calls
+      this.setState((prevState) => {
+        return {
+          widgets: update(prevState.widgets, {
+            [widget.id]: {
+              problem: {
+                mc_options: {
+                  $set: []
+                }
+              }
+            }
+          }),
+          deletingMCWidget: false
+        }
+      })
+    }
+  }
+
+  /**
+   * This method creates a widget object and adds it to the corresponding problem
+   * @param problemWidget The widget the mc option belongs to
+   * @param data the mc option
+   */
+  createNewMCOWidget = (problemWidget, data) => {
+    this.setState((prevState) => {
+      return {
+        widgets: update(prevState.widgets, {
+          [this.state.selectedWidgetId]: {
+            problem: {
+              mc_options: {
+                $push: [data]
+              }
+            }
+          }
+        })
+      }
+    })
+  }
+
+  /**
+   * This method is called when the mcq widget is moved. The positions of the options are stored separately and they
+  * all need to be updated
+   * @param widget the problem widget that includes the mcq widget
+   * @param data the new location of the mcq widget (the location of the top-left corner)
+   */
+  updateMCWidgetPosition = (widget, data) => {
+    let newMCO = widget.problem.mc_options.map((option, i) => {
+      return {
+        'widget': {
+          'x': {
+            $set: data.x + i * 24
+          },
+          'y': {
+            // each mc option needs to be positioned next to the previous option and should not overlap it
+            $set: data.y
+          }
+        }
+      }
+    })
+
+    // update the state with the new locations
+    this.setState(prevState => ({
+      widgets: update(prevState.widgets, {
+        [widget.id]: {
+          'problem': {
+            'mc_options': newMCO
+          }
+        }
+      })
+    }))
+  }
+
+  /**
+   * This method generates MC options by making the right calls to the api and creating
+   * the widget object in the mc_options array of the corresponding problem.
+   * @param problemWidget the problem widget the mc options belong to
+   * @param labels the labels for the options
+   * @param index the index in the labels array (the function is recusive, this index is increased)
+   * @param xPos x position of the current option
+   * @param yPos y position of the current option
+   */
+  generateAnswerBoxes = (problemWidget, labels, index, xPos, yPos) => {
+    if (labels.length === index) return
+
+    let data = {
+      'label': labels[index],
+      'problem_id': problemWidget.problem.id,
+      'feedback_id': null,
+      'widget': {
+        'name': 'mc_option_' + labels[index],
+        'x': xPos,
+        'y': yPos,
+        'type': 'mcq_widget'
+      }
+    }
+
+    const formData = new window.FormData()
+    formData.append('name', data.widget.name)
+    formData.append('x', data.widget.x)
+    formData.append('y', data.widget.y)
+    formData.append('problem_id', data.problem_id)
+    formData.append('label', data.label)
+    api.put('mult-choice/', formData).then(result => {
+      data.id = result.mult_choice_id
+      this.createNewMCOWidget(problemWidget, data)
+      this.generateAnswerBoxes(problemWidget, labels, index + 1, xPos + 24, yPos)
+    }).catch(err => {
+      console.log(err)
+    })
+  }
+
   SidePanel = (props) => {
     const selectedWidgetId = this.state.selectedWidgetId
     let selectedWidget = selectedWidgetId && this.state.widgets[selectedWidgetId]
@@ -241,11 +387,16 @@ class Exams extends React.Component {
     let widgetEditDisabled = this.state.previewing || !problem
     let isGraded = problem && problem.graded
     let widgetDeleteDisabled = widgetEditDisabled || isGraded
+    let totalNrAnswers = 12 // the upper limit for the nr of possible answer boxes
+    let containsMCOptions = (problem && problem.mc_options.length > 0) || false
+    let disabledDeleteBoxes = !containsMCOptions
+    let isMCQ = (problem && problem.isMCQ) || false
 
     return (
       <React.Fragment>
         <this.PanelEdit
           disabledEdit={widgetEditDisabled}
+          disableIsMCQ={widgetEditDisabled || containsMCOptions}
           disabledDelete={widgetDeleteDisabled}
           onDeleteClick={() => {
             this.setState({deletingWidget: true})
@@ -266,7 +417,42 @@ class Exams extends React.Component {
             }))
           }}
           saveProblemName={this.saveProblemName}
+          isMCQProblem={isMCQ}
+          onMCQChange={
+            (checked) => {
+              this.setState(prevState => ({
+                changedWidgetId: selectedWidgetId,
+                widgets: update(prevState.widgets, {
+                  [selectedWidgetId]: {
+                    problem: {
+                      isMCQ: {
+                        $set: checked
+                      }
+                    }
+                  }
+                })
+              }))
+            }
+          }
         />
+        { isMCQ ? (
+          <PanelMCQ
+            totalNrAnswers={totalNrAnswers}
+            disabledGenerateBoxes={containsMCOptions}
+            disabledDeleteBoxes={disabledDeleteBoxes}
+            problem={problem}
+            onGenerateBoxesClick={(labels) => {
+              let problemWidget = this.state.widgets[this.state.selectedWidgetId]
+              // position the new mc option widget inside the problem widget
+              let xPos = problemWidget.x + 2
+              let yPos = problemWidget.y + 2
+              this.generateAnswerBoxes(problemWidget, labels, 0, xPos, yPos)
+            }}
+            onDeleteBoxesClick={() => {
+              this.setState({deletingMCWidget: true})
+            }}
+          />
+        ) : null }
         <this.PanelExamActions />
       </React.Fragment>
     )
@@ -280,14 +466,18 @@ class Exams extends React.Component {
         <p className='panel-heading'>
           Problem details
         </p>
-        <div className='panel-block'>
-          <div className='field'>
-            {selectedWidgetId === null ? (
-              <p style={{margin: '0.625em 0', minHeight: '3em'}}>
+        {selectedWidgetId === null ? (
+          <div className='panel-block'>
+            <div className='field'>
+              <p style={{ margin: '0.625em 0', minHeight: '3em' }}>
                 To create a problem, draw a rectangle on the exam.
               </p>
-            ) : (
-              <React.Fragment>
+            </div>
+          </div>
+        ) : (
+          <React.Fragment>
+            <div className='panel-block'>
+              <div className='field'>
                 <label className='label'>Name</label>
                 <div className='control'>
                   <input
@@ -300,12 +490,24 @@ class Exams extends React.Component {
                     }}
                     onBlur={(e) => {
                       props.saveProblemName(e.target.value)
-                    }} />
+                    }}
+                  />
                 </div>
-              </React.Fragment>
-            )}
-          </div>
-        </div>
+              </div>
+            </div>
+            <div className='panel-block'>
+              <div className='field'>
+                <label className='label'>
+                  <input disabled={props.disableIsMCQ} type='checkbox' checked={props.isMCQProblem} onChange={
+                    (e) => {
+                      props.onMCQChange(e.target.checked)
+                    }} />
+                    Multiple choice question
+                </label>
+              </div>
+            </div>
+          </React.Fragment>
+        )}
         <div className='panel-block'>
           <button
             disabled={props.disabledDelete}
@@ -315,7 +517,6 @@ class Exams extends React.Component {
             Delete problem
           </button>
         </div>
-
       </nav>
     )
   }
@@ -451,6 +652,18 @@ class Exams extends React.Component {
         onCancel={() => this.setState({deletingWidget: false})}
         onConfirm={() => this.deleteWidget(this.state.selectedWidgetId)}
       />
+      <ConfirmationModal
+        active={this.state.deletingMCWidget && this.state.selectedWidgetId != null}
+        color='is-danger'
+        headerText={`Are you sure you want to delete the multiple choice options for problem "${
+          this.state.selectedWidgetId &&
+          this.state.widgets[this.state.selectedWidgetId] &&
+          this.state.widgets[this.state.selectedWidgetId].problem &&
+          this.state.widgets[this.state.selectedWidgetId].problem.name}"`}
+        confirmText='Delete multiple choice options'
+        onCancel={() => this.setState({deletingMCWidget: false})}
+        onConfirm={() => this.deleteMCWidget(this.state.selectedWidgetId)}
+      />
     </div>
   }
 }
diff --git a/client/views/ExamEditor.jsx b/client/views/ExamEditor.jsx
index 89cf1d8d163c9ace55510395de54147c9d694b96..15781e4c19b4aa826c3fb22667c62393a41cfeb9 100644
--- a/client/views/ExamEditor.jsx
+++ b/client/views/ExamEditor.jsx
@@ -8,6 +8,7 @@ import studentIdExampleImage from '../components/student_id_example.png'
 // FIXME!
 // eslint-disable-next-line import/no-webpack-loader-syntax
 import studentIdExampleImageSize from '!image-dimensions-loader!../components/student_id_example.png'
+import answerBoxImage from '../components/answer_box.png'
 import EmptyPDF from '../components/EmptyPDF.jsx'
 import PDFOverlay from '../components/PDFOverlay.jsx'
 
@@ -86,13 +87,16 @@ class ExamEditor extends React.Component {
       if (selectionBox.width >= this.props.problemMinWidth && selectionBox.height >= this.props.problemMinHeight) {
         const problemData = {
           name: 'New problem', // TODO: Name
-          page: this.props.page
+          page: this.props.page,
+          mc_options: [],
+          isMCQ: false
         }
         const widgetData = {
           x: Math.round(selectionBox.left),
           y: Math.round(selectionBox.top),
           width: Math.round(selectionBox.width),
-          height: Math.round(selectionBox.height)
+          height: Math.round(selectionBox.height),
+          type: 'problem_widget'
         }
         const formData = new window.FormData()
         formData.append('exam_id', this.props.examID)
@@ -169,131 +173,281 @@ class ExamEditor extends React.Component {
     }
   }
 
+  /**
+   * This method is called when the position of a widget has changed. It informs the server about the relocation.
+   * @param widget the widget that was relocated
+   * @param data  the new location
+   */
+  updateWidgetPositionDB = (widget, data) => {
+    api.patch('widgets/' + widget.id, data).then(() => {
+      // ok
+    }).catch(err => {
+      console.log(err)
+      // update to try and get a consistent state
+      this.props.updateExam()
+    })
+  }
+  /**
+   * This function renders a group of options into one draggable widget
+   * @returns {*}
+   */
+  renderMCWidget = (widget) => {
+    let width = 24 * widget.problem.mc_options.length
+    let height = 38
+    let enableResizing = false
+    const isSelected = widget.id === this.props.selectedWidgetId
+    return (
+      <ResizeAndDrag
+        key={'widget_mc_' + widget.id}
+        bounds={'[data-key="widget_' + widget.id + '"]'}
+        minWidth={width}
+        minHeight={height}
+        enableResizing={{
+          bottom: enableResizing,
+          bottomLeft: enableResizing,
+          bottomRight: enableResizing,
+          left: enableResizing,
+          right: enableResizing,
+          top: enableResizing,
+          topLeft: enableResizing,
+          topRight: enableResizing
+        }}
+        position={{
+          x: widget.problem.mc_options[0].widget.x,
+          y: widget.problem.mc_options[0].widget.y
+        }}
+        size={{
+          width: width,
+          height: height
+        }}
+        onDragStart={() => {
+          this.props.selectWidget(widget.id)
+        }}
+        onDragStop={(e, data) => {
+          this.props.updateMCWidgetPosition(widget, {
+            x: Math.round(data.x),
+            y: Math.round(data.y)
+          })
+
+          widget.problem.mc_options.forEach(
+            (option, i) => {
+              let newData = {
+                x: Math.round(data.x),
+                y: Math.round(data.y) + i * 24
+              }
+              this.updateWidgetPositionDB(option, newData)
+            })
+        }}
+      >
+        <div className={isSelected ? 'mcq-widget widget selected' : 'mcq-widget widget '}>
+          {widget.problem.mc_options.map((option) => {
+            return (
+              <div key={'widget_mco_' + option.id} className='mcq-option'>
+                <div className='mcq-option-label'>
+                  {option.label}
+                </div>
+                <img className='mcq-box' src={answerBoxImage} />
+              </div>
+            )
+          })}
+        </div>
+      </ResizeAndDrag>
+    )
+  }
+
+  /**
+   * Render problem widget and the mc options that correspond to the problem
+   * @param widget the corresponding widget object from the db
+   * @returns {Array}
+   */
+  renderProblemWidget = (widget) => {
+    // Only render when numPage is set
+    if (widget.problem.page !== this.props.page) return []
+
+    let enableResizing = true
+    const isSelected = widget.id === this.props.selectedWidgetId
+    let minWidth = this.props.problemMinWidth
+    let minHeight = this.props.problemMinHeight
+    let elementList = [(
+      <ResizeAndDrag
+        key={'widget_' + widget.id}
+        data-key={'widget_' + widget.id}
+        bounds='parent'
+        minWidth={minWidth}
+        minHeight={minHeight}
+        enableResizing={{
+          bottom: enableResizing,
+          bottomLeft: enableResizing,
+          bottomRight: enableResizing,
+          left: enableResizing,
+          right: enableResizing,
+          top: enableResizing,
+          topLeft: enableResizing,
+          topRight: enableResizing
+        }}
+        position={{
+          x: widget.x,
+          y: widget.y
+        }}
+        size={{
+          width: widget.width,
+          height: widget.height
+        }}
+        onResize={(e, direction, ref, delta, position) => {
+          this.props.updateWidget(widget.id, {
+            width: { $set: ref.offsetWidth },
+            height: { $set: ref.offsetHeight },
+            x: { $set: Math.round(position.x) },
+            y: { $set: Math.round(position.y) }
+          })
+        }}
+        onResizeStop={(e, direction, ref, delta, position) => {
+          api.patch('widgets/' + widget.id, {
+            x: Math.round(position.x),
+            y: Math.round(position.y),
+            width: ref.offsetWidth,
+            height: ref.offsetHeight
+          }).then(() => {
+            // ok
+          }).catch(err => {
+            console.log(err)
+            // update to try and get a consistent state
+            this.props.updateExam()
+          })
+        }}
+        onDragStart={() => {
+          this.props.selectWidget(widget.id)
+        }}
+        onDragStop={(e, data) => {
+          this.props.updateWidget(widget.id, {
+            x: { $set: Math.round(data.x) },
+            y: { $set: Math.round(data.y) }
+          })
+          api.patch('widgets/' + widget.id, {
+            x: Math.round(data.x),
+            y: Math.round(data.y)
+          }).then(() => {
+            // ok
+          }).catch(err => {
+            console.log(err)
+            // update to try and get a consistent state
+            this.props.updateExam()
+          })
+        }}
+      >
+        <div
+          className={isSelected ? 'widget selected' : 'widget'}
+        />
+      </ResizeAndDrag>
+    )]
+
+    // depending on the rendering option, render the mc_options separately or in a single widget
+    if (widget.problem.mc_options.length > 0 && !this.props.finalized) {
+      elementList.push(this.renderMCWidget(widget))
+    }
+
+    return elementList
+  }
+
+  /**
+   * Render exam widgets.
+   * @param widget the corresponding widget object from the db
+   * @returns {Array}
+   */
+  renderExamWidget = (widget) => {
+    if (this.props.finalized) return []
+
+    let minWidth, minHeight
+    let enableResizing = false
+    const isSelected = widget.id === this.props.selectedWidgetId
+    let image
+    if (widget.name === 'barcode_widget') {
+      minWidth = barcodeExampleImageSize.width
+      minHeight = barcodeExampleImageSize.height
+      image = barcodeExampleImage
+    } else if (this.props.page === 0 && widget.name === 'student_id_widget') {
+      minWidth = studentIdExampleImageSize.width
+      minHeight = studentIdExampleImageSize.height
+      image = studentIdExampleImage
+    } else {
+      return []
+    }
+
+    return [(
+      <ResizeAndDrag
+        key={'widget_' + widget.id}
+        bounds='parent'
+        minWidth={minWidth}
+        minHeight={minHeight}
+        enableResizing={{
+          bottom: enableResizing,
+          bottomLeft: enableResizing,
+          bottomRight: enableResizing,
+          left: enableResizing,
+          right: enableResizing,
+          top: enableResizing,
+          topLeft: enableResizing,
+          topRight: enableResizing
+        }}
+        position={{
+          x: widget.x,
+          y: widget.y
+        }}
+        size={{
+          width: widget.width,
+          height: widget.height
+        }}
+        onDragStart={() => {
+          this.props.selectWidget(widget.id)
+        }}
+        onDragStop={(e, data) => {
+          this.props.updateWidget(widget.id, {
+            x: { $set: Math.round(data.x) },
+            y: { $set: Math.round(data.y) }
+          })
+          api.patch('widgets/' + widget.id, {
+            x: Math.round(data.x),
+            y: Math.round(data.y)
+          }).then(() => {
+            // ok
+          }).catch(err => {
+            console.log(err)
+            // update to try and get a consistent state
+            this.props.updateExam()
+          })
+        }}
+      >
+        <div
+          className={isSelected ? 'widget selected' : 'widget'}
+          style={{
+            boxSizing: 'content-box',
+            backgroundImage: 'url(' + image + ')',
+            backgroundRepeat: 'no-repeat'
+          }}
+        />
+      </ResizeAndDrag>
+    )]
+  }
+
+  /**
+   * Render all the widgets by calling the right rendering function for each widget type
+   * @returns {Array}
+   */
   renderWidgets = () => {
     // Only render when numPage is set
     if (this.props.numPages !== null && this.props.widgets) {
-      const widgets = this.props.widgets.filter(widget => {
-        if (widget.name === 'student_id_widget' ||
-          widget.name === 'barcode_widget') {
-          return !this.props.finalized
-        } else if (widget.problem) {
-          return widget.problem.page === this.props.page
-        } else {
-          return true
-        }
-      })
+      let widgets = this.props.widgets
+      let elementList = []
 
-      let minWidth
-      let minHeight
-      let view
-      let enableResizing
-      return widgets.map((widget) => {
-        const isSelected = widget.id === this.props.selectedWidgetId
-
-        if (widget.problem) {
-          minWidth = this.props.problemMinWidth
-          minHeight = this.props.problemMinHeight
-          view = (
-            <div
-              className={isSelected ? 'widget selected' : 'widget'}
-            />
-          )
-          enableResizing = true
-        } else {
-          let image
-          if (widget.name === 'barcode_widget') {
-            minWidth = barcodeExampleImageSize.width
-            minHeight = barcodeExampleImageSize.height
-            image = barcodeExampleImage
-          } else if (this.props.page === 0 && widget.name === 'student_id_widget') {
-            minWidth = studentIdExampleImageSize.width
-            minHeight = studentIdExampleImageSize.height
-            image = studentIdExampleImage
-          } else {
-            return null
-          }
-          view = (
-            <div
-              className={isSelected ? 'widget selected' : 'widget'}
-              style={{
-                boxSizing: 'content-box',
-                backgroundImage: 'url(' + image + ')',
-                backgroundRepeat: 'no-repeat'
-              }}
-            />
-          )
-          enableResizing = false
+      widgets.forEach((widget) => {
+        if (widget.type === 'exam_widget') {
+          elementList = elementList.concat(this.renderExamWidget(widget))
+        } else if (widget.type === 'problem_widget') {
+          elementList = elementList.concat(this.renderProblemWidget(widget))
         }
-        return (
-          <ResizeAndDrag
-            key={'widget_' + widget.id}
-            bounds='parent'
-            minWidth={minWidth}
-            minHeight={minHeight}
-            enableResizing={{
-              bottom: enableResizing,
-              bottomLeft: enableResizing,
-              bottomRight: enableResizing,
-              left: enableResizing,
-              right: enableResizing,
-              top: enableResizing,
-              topLeft: enableResizing,
-              topRight: enableResizing
-            }}
-            position={{
-              x: widget.x,
-              y: widget.y
-            }}
-            size={{
-              width: widget.width,
-              height: widget.height
-            }}
-            onResize={(e, direction, ref, delta, position) => {
-              this.props.updateWidget(widget.id, {
-                width: { $set: ref.offsetWidth },
-                height: { $set: ref.offsetHeight },
-                x: { $set: Math.round(position.x) },
-                y: { $set: Math.round(position.y) }
-              })
-            }}
-            onResizeStop={(e, direction, ref, delta, position) => {
-              api.patch('widgets/' + widget.id, {
-                x: Math.round(position.x),
-                y: Math.round(position.y),
-                width: ref.offsetWidth,
-                height: ref.offsetHeight
-              }).then(() => {
-                // ok
-              }).catch(err => {
-                console.log(err)
-                // update to try and get a consistent state
-                this.updateExam()
-              })
-            }}
-            onDragStart={() => {
-              this.props.selectWidget(widget.id)
-            }}
-            onDragStop={(e, data) => {
-              this.props.updateWidget(widget.id, {
-                x: { $set: Math.round(data.x) },
-                y: { $set: Math.round(data.y) }
-              })
-              api.patch('widgets/' + widget.id, {
-                x: Math.round(data.x),
-                y: Math.round(data.y)
-              }).then(() => {
-                // ok
-              }).catch(err => {
-                console.log(err)
-                // update to try and get a consistent state
-                this.updateExam()
-              })
-            }}
-          >
-            {view}
-          </ResizeAndDrag>
-        )
       })
+
+      return elementList
     }
   }
 
diff --git a/data/course.sqlite b/data/course.sqlite
index 234038aee11424456894a18d144754cc951e9843..42369d0718bc1a16a99c196ae7dcd845a0a3ab30 100644
Binary files a/data/course.sqlite and b/data/course.sqlite differ
diff --git a/zesje/api/exams.py b/zesje/api/exams.py
index 554b3591642ff4a87dfbba2aa650ce951476c45b..5234178e7d35ef07c2c02dda45641521cbc1655a 100644
--- a/zesje/api/exams.py
+++ b/zesje/api/exams.py
@@ -181,18 +181,20 @@ class Exams(Resource):
                         'y': prob.widget.y,
                         'width': prob.widget.width,
                         'height': prob.widget.height,
+                        'type': prob.widget.type
                     },
                     'graded': any([sol.graded_by is not None for sol in prob.solutions]),
                     'mc_options': [
                         {
-                             'id': mc_option.id,
-                             'label': mc_option.label,
-                             'feedback_id': mc_option.feedback_id,
-                             'widget': {
-                                 'name': mc_option.name,
-                                 'x': mc_option.x,
-                                 'y': mc_option.y
-                             }
+                            'id': mc_option.id,
+                            'label': mc_option.label,
+                            'feedback_id': mc_option.feedback_id,
+                            'widget': {
+                                'name': mc_option.name,
+                                'x': mc_option.x,
+                                'y': mc_option.y,
+                                'type': mc_option.type
+                            }
                         } for mc_option in prob.mc_options
                     ]
                 } for prob in exam.problems  # Sorted by prob.id
@@ -203,6 +205,7 @@ class Exams(Resource):
                     'name': widget.name,
                     'x': widget.x,
                     'y': widget.y,
+                    'type': widget.type
                 } for widget in exam.widgets  # Sorted by widget.id
             ],
             'finalized': exam.finalized,