diff --git a/opentech/static_src/src/app/src/components/RichTextForm/index.js b/opentech/static_src/src/app/src/components/RichTextForm/index.js
index dcaad92bcb750d14b0c7fbd2f4dbf15440caaca5..7934c274885104b54ecea2bdff51752866cbf87c 100644
--- a/opentech/static_src/src/app/src/components/RichTextForm/index.js
+++ b/opentech/static_src/src/app/src/components/RichTextForm/index.js
@@ -11,6 +11,7 @@ export default class RichTextForm extends React.Component {
         disabled: PropTypes.bool.isRequired,
         initialValue: PropTypes.string,
         onValueChange: PropTypes.func,
+        value: PropTypes.string,
     };
 
     render() {
@@ -18,6 +19,7 @@ export default class RichTextForm extends React.Component {
             disabled: this.props.disabled,
             defaultValue: this.props.initialValue,
             onChange: this.handleValueChange,
+            value: this.props.value,
         };
         return (
             <textarea {...passProps} />
diff --git a/opentech/static_src/src/app/src/containers/AddNoteForm.js b/opentech/static_src/src/app/src/containers/AddNoteForm.js
index 4a46b3a366515aff5bf3c67e22c21605d24703da..3a92dc695dc15fe94f319a5491d56581d80335d5 100644
--- a/opentech/static_src/src/app/src/containers/AddNoteForm.js
+++ b/opentech/static_src/src/app/src/containers/AddNoteForm.js
@@ -4,11 +4,17 @@ import PropTypes from 'prop-types';
 
 import { createNoteForSubmission } from '@actions/notes';
 import RichTextForm from '@components/RichTextForm';
+import {
+    getNoteCreatingErrorForSubmission,
+    getNoteCreatingStateForSubmission,
+} from '@selectors/notes';
 
 class AddNoteForm extends React.Component {
     static propTypes = {
         submitNote: PropTypes.func,
         submissionID: PropTypes.number,
+        error: PropTypes.any,
+        isCreating: PropTypes.bool,
     };
 
     state = {
@@ -16,30 +22,50 @@ class AddNoteForm extends React.Component {
     };
 
     render() {
+        const { error, isCreating } = this.props;
         return (
             <>
-                <RichTextForm onValueChange={this.setText} />
-                <button onClick={this.onSubmit}>Submit</button>
+                {Boolean(error) && <p>{error}</p>}
+                <RichTextForm
+                    disabled={isCreating}
+                    value={this.state.text}
+                    onValueChange={this.setText} />
+                <button
+                    disabled={!this.state.text.trim() || isCreating}
+                    onClick={this.onSubmit}
+                >
+                    Submit
+                </button>
             </>
         );
     }
 
-    onSubmit = () => {
-        this.props.submitNote(this.props.submissionID, {
-            message: this.state.text,
+    onSubmit = async () => {
+        const action = await this.props.submitNote(this.props.submissionID, {
+            message: this.state.text.trim(),
             visibility: 'internal',
         });
+        if (action === true) {
+            this.setState({
+                text: ''
+            });
+        }
     }
 
     setText = text => {
         this.setState({
-            text: text.trim(),
+            text
         });
     }
 }
 
+const mapStateToProps = (state, ownProps) => ({
+    error: getNoteCreatingErrorForSubmission(ownProps.submissionID)(state),
+    isCreating: getNoteCreatingStateForSubmission(ownProps.submissionID)(state),
+});
+
 const mapDispatchToProps = dispatch => ({
     submitNote: (submissionID, note) => dispatch(createNoteForSubmission(submissionID, note)),
 });
 
-export default connect(null, mapDispatchToProps)(AddNoteForm);
+export default connect(mapStateToProps, mapDispatchToProps)(AddNoteForm);
diff --git a/opentech/static_src/src/app/src/redux/actions/notes.js b/opentech/static_src/src/app/src/redux/actions/notes.js
index d7ebe1e657c139ec24a5d9812a9847ba02067ec1..49b3bacde145424d05dfbedaacac0b5aef7f1380 100644
--- a/opentech/static_src/src/app/src/redux/actions/notes.js
+++ b/opentech/static_src/src/app/src/redux/actions/notes.js
@@ -1,4 +1,4 @@
-import { updateSubmission } from '@actions/submissions';
+import { updateSubmission, appendNoteIDForSubmission } from '@actions/submissions';
 import api from '@api';
 
 export const FAIL_FETCHING_NOTES = 'FAIL_FETCHING_NOTES';
@@ -6,6 +6,9 @@ export const START_FETCHING_NOTES = 'START_FETCHING_NOTES';
 export const UPDATE_NOTES = 'UPDATE_NOTES';
 export const UPDATE_NOTE = 'UPDATE_NOTE';
 
+export const START_CREATING_NOTE_FOR_SUBMISSION = 'START_CREATING_NOTE_FOR_SUBMISSION';
+export const FAIL_CREATING_NOTE_FOR_SUBMISSION = 'FAIL_CREATING_NOTE_FOR_SUBMISSION';
+
 const startFetchingNotes = () => ({
     type: START_FETCHING_NOTES,
 });
@@ -45,20 +48,47 @@ export const updateNotes = data => ({
     data,
 });
 
+const startCreatingNoteForSubmission = submissionID => ({
+    type: START_CREATING_NOTE_FOR_SUBMISSION,
+    submissionID
+});
+
+const failCreatingNoteForSubmission = (submissionID, error) => ({
+    type: FAIL_CREATING_NOTE_FOR_SUBMISSION,
+    submissionID,
+    error
+});
+
+const updateNote = (data, submissionID) => ({
+    type: UPDATE_NOTE,
+    submissionID,
+    data,
+});
+
+const createdNoteForSubmission = (submissionID, data) => {
+    return function(dispatch) {
+        dispatch(updateNote(data, submissionID));
+        dispatch(appendNoteIDForSubmission(submissionID, data.id));
+        return true;
+    };
+};
 
 export const createNoteForSubmission = (submissionID, note) => {
     return async function(dispatch) {
+        dispatch(startCreatingNoteForSubmission(submissionID));
         try {
             const response = await api.createNoteForSubmission(submissionID, note);
             const json = await response.json();
             if (!response.ok) {
-                console.error(json);
-                return;
+                return dispatch(failCreatingNoteForSubmission(
+                    submissionID,
+                    JSON.stringify(json)
+                ));
             }
-            return;
+            return dispatch(createdNoteForSubmission(submissionID, json));
         } catch (e) {
             console.error(e);
-            return;
+            return dispatch(failCreatingNoteForSubmission(submissionID, e.message));
         }
     }
-}
+};
diff --git a/opentech/static_src/src/app/src/redux/actions/submissions.js b/opentech/static_src/src/app/src/redux/actions/submissions.js
index 181f755f4fb588a3338a82c948b5ecd6a9b9a8ec..96014f0c50bfe0f40ffa2b2a7ccd15d037945393 100644
--- a/opentech/static_src/src/app/src/redux/actions/submissions.js
+++ b/opentech/static_src/src/app/src/redux/actions/submissions.js
@@ -20,6 +20,9 @@ export const FAIL_LOADING_SUBMISSION = 'FAIL_LOADING_SUBMISSION';
 export const UPDATE_SUBMISSION = 'UPDATE_SUBMISSION';
 export const CLEAR_CURRENT_SUBMISSION = 'CLEAR_CURRENT_SUBMISSION';
 
+// Notes
+export const APPEND_NOTE_ID_FOR_SUBMISSION = 'APPEND_NOTE_ID_FOR_SUBMISSION';
+
 export const setCurrentSubmissionRound = id => ({
     type: SET_CURRENT_SUBMISSION_ROUND,
     id,
@@ -132,3 +135,9 @@ export const updateSubmission = (submissionID, data) => ({
 export const clearCurrentSubmission = () => ({
     type: CLEAR_CURRENT_SUBMISSION,
 });
+
+export const appendNoteIDForSubmission = (submissionID, noteID) => ({
+    type: APPEND_NOTE_ID_FOR_SUBMISSION,
+    submissionID,
+    noteID,
+});
diff --git a/opentech/static_src/src/app/src/redux/reducers/notes.js b/opentech/static_src/src/app/src/redux/reducers/notes.js
index 4137c6103999494d66ad54784cbb75397b974a0e..eeca41483008eb448e9dd860d483a0af6a3b4a9f 100644
--- a/opentech/static_src/src/app/src/redux/reducers/notes.js
+++ b/opentech/static_src/src/app/src/redux/reducers/notes.js
@@ -5,6 +5,8 @@ import {
     UPDATE_NOTES,
     START_FETCHING_NOTES,
     FAIL_FETCHING_NOTES,
+    START_CREATING_NOTE_FOR_SUBMISSION,
+    FAIL_CREATING_NOTE_FOR_SUBMISSION,
 } from '@actions/notes';
 
 function notesFetching(state = false, action) {
@@ -43,8 +45,44 @@ function note(state, action) {
     }
 }
 
+function notesCreating(state = [], action) {
+    switch (action.type) {
+        case START_CREATING_NOTE_FOR_SUBMISSION:
+            return [
+                ...state,
+                action.submissionID,
+            ];
+        case UPDATE_NOTE:
+        case FAIL_CREATING_NOTE_FOR_SUBMISSION:
+            return state.filter(v => v !== action.submissionID);
+        default:
+            return state
+    }
+}
+
+
+function notesFailedCreating(state = {}, action) {
+    switch (action.type) {
+        case UPDATE_NOTE:
+        case START_CREATING_NOTE_FOR_SUBMISSION:
+            return Object.entries(state).reduce((acc, [k, v]) => {
+                if (k !== action.submissionID) {
+                    acc[k] = v;
+                }
+                return acc;
+            }, {});
+        case FAIL_CREATING_NOTE_FOR_SUBMISSION:
+            return {
+                ...state,
+                [action.submissionID]: action.error,
+            };
+        default:
+            return state
+    }
+}
+
 function notesByID(state = {}, action) {
-    switch(action.type) {
+    switch (action.type) {
         case UPDATE_NOTES:
             return {
                 ...state,
@@ -56,6 +94,14 @@ function notesByID(state = {}, action) {
                     return newNotesAccumulator;
                 }, {}),
             };
+        case UPDATE_NOTE:
+            return {
+                ...state,
+                [action.data.id]: note(state[action.data.id], {
+                    type: UPDATE_NOTE,
+                    data: action.data,
+                }),
+            };
         default:
             return state;
     }
@@ -65,4 +111,6 @@ export default combineReducers({
     byID: notesByID,
     isFetching: notesFetching,
     isErrored: notesErrored,
+    createError: notesFailedCreating,
+    isCreating: notesCreating,
 });
diff --git a/opentech/static_src/src/app/src/redux/reducers/submissions.js b/opentech/static_src/src/app/src/redux/reducers/submissions.js
index 7563d1e25f0ac19364f82d0c96af3624f2125d4c..d77288614357140ace384fad7de9cb3aa03b8240 100644
--- a/opentech/static_src/src/app/src/redux/reducers/submissions.js
+++ b/opentech/static_src/src/app/src/redux/reducers/submissions.js
@@ -7,6 +7,7 @@ import {
     UPDATE_SUBMISSIONS_BY_ROUND,
     UPDATE_SUBMISSION,
     SET_CURRENT_SUBMISSION,
+    APPEND_NOTE_ID_FOR_SUBMISSION,
 } from '@actions/submissions';
 
 
@@ -31,6 +32,14 @@ function submission(state, action) {
                 isFetching: false,
                 isErrored: false,
             };
+        case APPEND_NOTE_ID_FOR_SUBMISSION:
+            return {
+                ...state,
+                comments: [
+                    action.noteID,
+                    ...state.comments
+                ]
+            };
         default:
             return state;
     }
@@ -41,6 +50,7 @@ function submissionsByID(state = {}, action) {
     switch(action.type) {
         case START_LOADING_SUBMISSION:
         case FAIL_LOADING_SUBMISSION:
+        case APPEND_NOTE_ID_FOR_SUBMISSION:
         case UPDATE_SUBMISSION:
             return {
                 ...state,
diff --git a/opentech/static_src/src/app/src/redux/selectors/notes.js b/opentech/static_src/src/app/src/redux/selectors/notes.js
index cf5ccc2fd82a54c81ba08884242409ac6b565117..cd035999ff96834f3262b618a24f43750aa251b8 100644
--- a/opentech/static_src/src/app/src/redux/selectors/notes.js
+++ b/opentech/static_src/src/app/src/redux/selectors/notes.js
@@ -16,3 +16,15 @@ export const getNoteIDsForSubmissionOfID = submissionID => createSelector(
     [getSubmissionOfID(submissionID)],
     submission => (submission || {}).comments || []
 );
+
+const getNoteCreatingErrors = state => state.notes.createError;
+
+export const getNoteCreatingErrorForSubmission = submissionID => createSelector(
+    [getNoteCreatingErrors], errors => errors[submissionID]
+);
+
+const getNoteCreatingState = state => state.notes.isCreating;
+
+export const getNoteCreatingStateForSubmission = submissionID => createSelector(
+    [getNoteCreatingState], creatingStates => creatingStates.includes(submissionID)
+);