diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index b1f8b00cab18a9f09d7b634239bc87f6111c73c2..889940cf9abe00d46a1e79c1881da6c9ec1e748f 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -43,6 +43,7 @@
 #include "llmath.h"
 
 #include "llclipboard.h"
+#include "llemojihelper.h"
 #include "llscrollbar.h"
 #include "llstl.h"
 #include "llstring.h"
@@ -238,6 +239,7 @@ LLTextEditor::Params::Params()
 	default_color("default_color"),
     commit_on_focus_lost("commit_on_focus_lost", false),
 	show_context_menu("show_context_menu"),
+	show_emoji_helper("show_emoji_helper"),
 	enable_tooltip_paste("enable_tooltip_paste")
 {
 	addSynonym(prevalidate_callback, "text_type");
@@ -259,6 +261,7 @@ LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) :
 	mPrevalidateFunc(p.prevalidate_callback()),
 	mContextMenu(NULL),
 	mShowContextMenu(p.show_context_menu),
+	mShowEmojiHelper(p.show_emoji_helper),
 	mEnableTooltipPaste(p.enable_tooltip_paste),
 	mPassDelete(FALSE),
 	mKeepSelectionOnReturn(false)
@@ -501,6 +504,15 @@ void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out,
 	}
 }
 
+void LLTextEditor::setShowEmojiHelper(bool show) {
+	if (!mShowEmojiHelper)
+	{
+		LLEmojiHelper::instance().hideHelper(this);
+	}
+
+	mShowEmojiHelper = show;
+}
+
 BOOL LLTextEditor::selectionContainsLineBreaks()
 {
 	if (hasSelection())
@@ -930,6 +942,12 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
 
 S32 LLTextEditor::execute( TextCmd* cmd )
 {
+	if (!mReadOnly && mShowEmojiHelper)
+	{
+		// Any change to our contents should always hide the helper
+		LLEmojiHelper::instance().hideHelper(this);
+	}
+
 	S32 delta = 0;
 	if( cmd->execute(this, &delta) )
 	{
@@ -1124,6 +1142,17 @@ void LLTextEditor::addChar(llwchar wc)
 
 	setCursorPos(mCursorPos + addChar( mCursorPos, wc ));
 
+	if (!mReadOnly && mShowEmojiHelper)
+	{
+		LLWString wtext(getWText()); S32 shortCodePos;
+		if (LLEmojiHelper::isCursorInEmojiCode(wtext, mCursorPos, &shortCodePos))
+		{
+			const LLRect cursorRect = getLocalRectFromDocIndex(mCursorPos);
+			const LLWString shortCode = wtext.substr(shortCodePos, mCursorPos);
+			LLEmojiHelper::instance().showHelper(this, cursorRect.mLeft, cursorRect.mTop, wstring_to_utf8str(shortCode));
+		}
+	}
+
 	if (!mReadOnly && mAutoreplaceCallback != NULL)
 	{
 		// autoreplace the text, if necessary
@@ -1774,6 +1803,11 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
 	}
 	else 
 	{
+		if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask))
+		{
+			return TRUE;
+		}
+
 		if (mEnableTooltipPaste &&
 			LLToolTipMgr::instance().toolTipVisible() && 
 			KEY_TAB == key)
@@ -1815,6 +1849,12 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
 	{
 		resetCursorBlink();
 		needsScroll();
+
+		if (mShowEmojiHelper)
+		{
+			// Dismiss the helper whenever we handled a key that it didn't
+			LLEmojiHelper::instance().hideHelper(this);
+		}
 	}
 
 	return handled;
diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h
index 26702b2412b8fdf4b2d81b01bb40f2f618b9b814..04910b6f68aacf9d87be6453e76fe9c8da6b3cc7 100644
--- a/indra/llui/lltexteditor.h
+++ b/indra/llui/lltexteditor.h
@@ -60,6 +60,7 @@ class LLTextEditor :
 								ignore_tab,
 								commit_on_focus_lost,
 								show_context_menu,
+								show_emoji_helper,
 								enable_tooltip_paste,
 								auto_indent;
 
@@ -201,6 +202,9 @@ class LLTextEditor :
 	void			setShowContextMenu(bool show) { mShowContextMenu = show; }
 	bool			getShowContextMenu() const { return mShowContextMenu; }
 
+	void			setShowEmojiHelper(bool show);
+	bool			getShowEmojiHelper() const { return mShowEmojiHelper; }
+
 	void			setPassDelete(BOOL b) { mPassDelete = b; }
 
 protected:
@@ -317,6 +321,7 @@ class LLTextEditor :
 
 	BOOL			mAllowEmbeddedItems;
 	bool			mShowContextMenu;
+	bool			mShowEmojiHelper;
 	bool			mEnableTooltipPaste;
 	bool			mPassDelete;
 	bool			mKeepSelectionOnReturn;	// disabling of removing selected text after pressing of Enter