diff --git a/client/modules/IDE/components/EditableInput.jsx b/client/modules/IDE/components/EditableInput.jsx
new file mode 100644
index 00000000..6315839e
--- /dev/null
+++ b/client/modules/IDE/components/EditableInput.jsx
@@ -0,0 +1,92 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import InlineSVG from 'react-inlinesvg';
+
+const editIconUrl = require('../../../images/pencil.svg');
+
+function EditIcon() {
+ return ;
+}
+
+function EditableInput({
+ validate, value, emptyPlaceholder, InputComponent, inputProps, onChange
+}) {
+ const [isEditing, setIsEditing] = React.useState(false);
+ const [currentValue, setCurrentValue] = React.useState(value || '');
+ const displayValue = currentValue || emptyPlaceholder;
+ const classes = `editable-input editable-input--${isEditing ? 'is-editing' : 'is-not-editing'}`;
+ const inputRef = React.createRef();
+
+ React.useEffect(() => {
+ if (isEditing) {
+ inputRef.current.focus();
+ }
+ }, [isEditing]);
+
+ function beginEditing() {
+ setIsEditing(true);
+ }
+
+ function doneEditing() {
+ setIsEditing(false);
+
+ const isValid = typeof validate === 'function' && validate(currentValue);
+
+ if (isValid) {
+ onChange(currentValue);
+ } else {
+ setCurrentValue(value);
+ }
+ }
+
+ function updateValue(event) {
+ setCurrentValue(event.target.value);
+ }
+
+ function checkForKeyAction(event) {
+ if (event.key === 'Enter') {
+ doneEditing();
+ }
+ }
+
+ return (
+
+
+
+
+
+ );
+}
+
+EditableInput.defaultProps = {
+ emptyPlaceholder: 'No value',
+ InputComponent: 'input',
+ inputProps: {},
+ validate: () => true,
+ value: '',
+};
+
+EditableInput.propTypes = {
+ emptyPlaceholder: PropTypes.string,
+ InputComponent: PropTypes.elementType,
+ // eslint-disable-next-line react/forbid-prop-types
+ inputProps: PropTypes.object,
+ onChange: PropTypes.func.isRequired,
+ validate: PropTypes.func,
+ value: PropTypes.string,
+};
+
+export default EditableInput;
diff --git a/client/styles/components/_editable-input.scss b/client/styles/components/_editable-input.scss
new file mode 100644
index 00000000..c7239d35
--- /dev/null
+++ b/client/styles/components/_editable-input.scss
@@ -0,0 +1,37 @@
+.editable-input {
+ height: 70%;
+ display: flex;
+ align-items: center;
+}
+
+.editable-input__label {
+ @include themify() {
+ color: getThemifyVariable('inactive-text-color');
+ &:hover {
+ color: getThemifyVariable('primary-text-color');
+ & .editable-input__icon path {
+ fill: getThemifyVariable('primary-text-color');
+ }
+ }
+ }
+ cursor: pointer;
+ line-height: #{18 / $base-font-size}rem;
+
+ font-size: unset;
+ font-weight: unset;
+}
+
+.editable-input__icon svg {
+ width: 1.5rem;
+ height: 1.5rem;
+}
+
+.editable-input--is-not-editing .editable-input__input,
+.editable-input--is-editing .editable-input__label {
+ display: none;
+}
+
+.editable-input--is-editing .editable-input__input,
+.editable-input--is-not-editing .editable-input__label {
+ display: block;
+}
diff --git a/client/styles/main.scss b/client/styles/main.scss
index 51d44581..128b0aee 100644
--- a/client/styles/main.scss
+++ b/client/styles/main.scss
@@ -48,6 +48,7 @@
@import 'components/uploader';
@import 'components/tabs';
@import 'components/dashboard-header';
+@import 'components/editable-input';
@import 'layout/dashboard';
@import 'layout/ide';