diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/PollApp2x.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/PollApp2x.scala
index 02f5cf78749bf68a56d93175d1cb625c93fc8b12..31dbeb73fa8f0c96b827a05728cdc63e42ff12ff 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/PollApp2x.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/PollApp2x.scala
@@ -6,6 +6,7 @@ import akka.event.Logging
 class PollApp2x(implicit val context: ActorContext)
   extends GetCurrentPollReqMsgHdlr
   with RespondToPollReqMsgHdlr
+  with RespondToTypedPollReqMsgHdlr
   with ShowPollResultReqMsgHdlr
   with StartCustomPollReqMsgHdlr
   with StartPollReqMsgHdlr
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/RespondToTypedPollReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/RespondToTypedPollReqMsgHdlr.scala
new file mode 100644
index 0000000000000000000000000000000000000000..b87f510dc2a6818e0d9d6ec6077049c87afbe78f
--- /dev/null
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/RespondToTypedPollReqMsgHdlr.scala
@@ -0,0 +1,51 @@
+package org.bigbluebutton.core.apps.polls
+
+import org.bigbluebutton.common2.domain.SimplePollResultOutVO
+import org.bigbluebutton.common2.msgs._
+import org.bigbluebutton.core.bus.MessageBus
+import org.bigbluebutton.core.models.Polls
+import org.bigbluebutton.core.running.{ LiveMeeting }
+import org.bigbluebutton.core.models.Users2x
+
+trait RespondToTypedPollReqMsgHdlr {
+  this: PollApp2x =>
+
+  def handle(msg: RespondToTypedPollReqMsg, liveMeeting: LiveMeeting, bus: MessageBus): Unit = {
+    log.debug("Received RespondToPollReqMsg {}", RespondToTypedPollReqMsg)
+
+    def broadcastPollUpdatedEvent(msg: RespondToTypedPollReqMsg, pollId: String, poll: SimplePollResultOutVO): Unit = {
+      val routing = Routing.addMsgToClientRouting(MessageTypes.BROADCAST_TO_MEETING, liveMeeting.props.meetingProp.intId, msg.header.userId)
+      val envelope = BbbCoreEnvelope(PollUpdatedEvtMsg.NAME, routing)
+      val header = BbbClientMsgHeader(PollUpdatedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
+
+      val body = PollUpdatedEvtMsgBody(pollId, poll)
+      val event = PollUpdatedEvtMsg(header, body)
+      val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
+      bus.outGW.send(msgEvent)
+    }
+
+    def broadcastUserRespondedToTypedPollRespMsg(msg: RespondToTypedPollReqMsg, pollId: String, answer: String, sendToId: String): Unit = {
+      val routing = Routing.addMsgToClientRouting(MessageTypes.DIRECT, liveMeeting.props.meetingProp.intId, sendToId)
+      val envelope = BbbCoreEnvelope(UserRespondedToTypedPollRespMsg.NAME, routing)
+      val header = BbbClientMsgHeader(UserRespondedToTypedPollRespMsg.NAME, liveMeeting.props.meetingProp.intId, sendToId)
+
+      val body = UserRespondedToTypedPollRespMsgBody(pollId, msg.header.userId, answer)
+      val event = UserRespondedToTypedPollRespMsg(header, body)
+      val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
+      bus.outGW.send(msgEvent)
+    }
+
+    for {
+      (pollId: String, updatedPoll: SimplePollResultOutVO) <- Polls.handleRespondToTypedPollReqMsg(msg.header.userId, msg.body.pollId,
+        msg.body.questionId, msg.body.answer, liveMeeting)
+    } yield {
+      broadcastPollUpdatedEvent(msg, pollId, updatedPoll)
+
+      for {
+        presenter <- Users2x.findPresenter(liveMeeting.users2x)
+      } yield {
+        broadcastUserRespondedToTypedPollRespMsg(msg, pollId, msg.body.answer, presenter.intId)
+      }
+    }
+  }
+}
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/StartCustomPollReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/StartCustomPollReqMsgHdlr.scala
index cf58f6109810e30dda9e7910dd2ce8eb030147fd..0065bc517a69240224262e9eea51b32f4d81fc76 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/StartCustomPollReqMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/StartCustomPollReqMsgHdlr.scala
@@ -17,7 +17,7 @@ trait StartCustomPollReqMsgHdlr extends RightsManagementTrait {
       val envelope = BbbCoreEnvelope(PollStartedEvtMsg.NAME, routing)
       val header = BbbClientMsgHeader(PollStartedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
 
-      val body = PollStartedEvtMsgBody(msg.header.userId, poll.id, poll)
+      val body = PollStartedEvtMsgBody(msg.header.userId, poll.id, msg.body.pollType, msg.body.question, poll)
       val event = PollStartedEvtMsg(header, body)
       val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
       bus.outGW.send(msgEvent)
@@ -29,7 +29,7 @@ trait StartCustomPollReqMsgHdlr extends RightsManagementTrait {
       PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
     } else {
       for {
-        pvo <- Polls.handleStartCustomPollReqMsg(state, msg.header.userId, msg.body.pollId, msg.body.pollType, msg.body.answers, liveMeeting)
+        pvo <- Polls.handleStartCustomPollReqMsg(state, msg.header.userId, msg.body.pollId, msg.body.pollType, msg.body.answers, msg.body.question, liveMeeting)
       } yield {
         broadcastEvent(msg, pvo)
       }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/StartPollReqMsgHdlr.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/StartPollReqMsgHdlr.scala
index c50e43335d79d95b022e7d837b792464d032796c..f01eaa74ac265d68de19f5348278d74570eb1b6f 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/StartPollReqMsgHdlr.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/apps/polls/StartPollReqMsgHdlr.scala
@@ -18,7 +18,7 @@ trait StartPollReqMsgHdlr extends RightsManagementTrait {
       val envelope = BbbCoreEnvelope(PollStartedEvtMsg.NAME, routing)
       val header = BbbClientMsgHeader(PollStartedEvtMsg.NAME, liveMeeting.props.meetingProp.intId, msg.header.userId)
 
-      val body = PollStartedEvtMsgBody(msg.header.userId, poll.id, poll)
+      val body = PollStartedEvtMsgBody(msg.header.userId, poll.id, msg.body.pollType, msg.body.question, poll)
       val event = PollStartedEvtMsg(header, body)
       val msgEvent = BbbCommonEnvCoreMsg(envelope, event)
       bus.outGW.send(msgEvent)
@@ -30,7 +30,7 @@ trait StartPollReqMsgHdlr extends RightsManagementTrait {
       PermissionCheck.ejectUserForFailedPermission(meetingId, msg.header.userId, reason, bus.outGW, liveMeeting)
     } else {
       for {
-        pvo <- Polls.handleStartPollReqMsg(state, msg.header.userId, msg.body.pollId, msg.body.pollType, liveMeeting)
+        pvo <- Polls.handleStartPollReqMsg(state, msg.header.userId, msg.body.pollId, msg.body.pollType, msg.body.question, liveMeeting)
       } yield {
         broadcastEvent(msg, pvo)
       }
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Polls.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Polls.scala
index 6bec9374607e1feca3773e4489efda00ae77cefd..99cc8f5bf2109a349975028c265c70b3871cdf2a 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Polls.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/models/Polls.scala
@@ -11,7 +11,7 @@ import org.bigbluebutton.core.running.LiveMeeting
 
 object Polls {
 
-  def handleStartPollReqMsg(state: MeetingState2x, userId: String, pollId: String, pollType: String,
+  def handleStartPollReqMsg(state: MeetingState2x, userId: String, pollId: String, pollType: String, question: String,
                             lm: LiveMeeting): Option[SimplePollOutVO] = {
 
     def createPoll(stampedPollId: String): Option[Poll] = {
@@ -156,8 +156,18 @@ object Polls {
 
   }
 
+  def handleRespondToTypedPollReqMsg(requesterId: String, pollId: String, questionId: Int, answer: String,
+                                     lm: LiveMeeting): Option[(String, SimplePollResultOutVO)] = {
+    for {
+      poll <- getSimplePollResult(pollId, lm.polls)
+      pvo <- handleRespondToTypedPoll(poll, requesterId, pollId, questionId, answer, lm)
+    } yield {
+      (pollId, pvo)
+    }
+  }
+
   def handleStartCustomPollReqMsg(state: MeetingState2x, requesterId: String, pollId: String, pollType: String,
-                                  answers: Seq[String], lm: LiveMeeting): Option[SimplePollOutVO] = {
+                                  answers: Seq[String], question: String, lm: LiveMeeting): Option[SimplePollOutVO] = {
 
     def createPoll(stampedPollId: String): Option[Poll] = {
       val numRespondents: Int = Users2x.numUsers(lm.users2x) - 1 // subtract the presenter
@@ -227,7 +237,17 @@ object Polls {
     } yield {
       updatedPoll
     }
+  }
+
+  private def handleRespondToTypedPoll(poll: SimplePollResultOutVO, requesterId: String, pollId: String, questionId: Int,
+                                       answer: String, lm: LiveMeeting): Option[SimplePollResultOutVO] = {
 
+    addQuestionResponse(poll.id, questionId, answer, lm.polls)
+    for {
+      updatedPoll <- getSimplePollResult(poll.id, lm.polls)
+    } yield {
+      updatedPoll
+    }
   }
 
   private def pollResultToWhiteboardShape(result: SimplePollResultOutVO): scala.collection.immutable.Map[String, Object] = {
@@ -363,6 +383,14 @@ object Polls {
     }
   }
 
+  def addQuestionResponse(pollId: String, questionID: Int, answer: String, polls: Polls) {
+    polls.polls.get(pollId) match {
+      case Some(p) => {
+        p.addQuestionResponse(questionID, answer)
+      }
+      case None =>
+    }
+  }
 }
 
 object PollType {
@@ -371,6 +399,7 @@ object PollType {
   val CustomPollType = "CUSTOM"
   val LetterPollType = "A-"
   val NumberPollType = "1-"
+  val ResponsePollType = "RP"
 }
 
 object PollFactory {
@@ -379,19 +408,19 @@ object PollFactory {
   val NumberArray = Array("1", "2", "3", "4", "5", "6")
 
   private def processYesNoPollType(qType: String): Question = {
-    val answers = new Array[Answer](2)
+    val answers = new ArrayBuffer[Answer];
 
-    answers(0) = new Answer(0, "Yes", Some("Yes"))
-    answers(1) = new Answer(1, "No", Some("No"))
+    answers += new Answer(0, "Yes", Some("Yes"))
+    answers += new Answer(1, "No", Some("No"))
 
     new Question(0, PollType.YesNoPollType, false, None, answers)
   }
 
   private def processTrueFalsePollType(qType: String): Question = {
-    val answers = new Array[Answer](2)
+    val answers = new ArrayBuffer[Answer];
 
-    answers(0) = new Answer(0, "True", Some("True"))
-    answers(1) = new Answer(1, "False", Some("False"))
+    answers += new Answer(0, "True", Some("True"))
+    answers += new Answer(1, "False", Some("False"))
 
     new Question(0, PollType.TrueFalsePollType, false, None, answers)
   }
@@ -403,10 +432,9 @@ object PollFactory {
     var questionOption: Option[Question] = None
 
     if (numQs > 0 && numQs <= 6) {
-      val answers = new Array[Answer](numQs)
-
+      val answers = new ArrayBuffer[Answer];
       for (i <- 0 until numQs) {
-        answers(i) = new Answer(i, LetterArray(i), Some(LetterArray(i)))
+        answers += new Answer(i, LetterArray(i), Some(LetterArray(i)))
         val question = new Question(0, PollType.LetterPollType, multiResponse, None, answers)
         questionOption = Some(question)
       }
@@ -422,9 +450,9 @@ object PollFactory {
     var questionOption: Option[Question] = None
 
     if (numQs > 0 && numQs <= 6) {
-      val answers = new Array[Answer](numQs)
+      val answers = new ArrayBuffer[Answer];
       for (i <- 0 until numQs) {
-        answers(i) = new Answer(i, NumberArray(i), Some(NumberArray(i)))
+        answers += new Answer(i, NumberArray(i), Some(NumberArray(i)))
         val question = new Question(0, PollType.NumberPollType, multiResponse, None, answers)
         questionOption = Some(question)
       }
@@ -432,10 +460,10 @@ object PollFactory {
     questionOption
   }
 
-  private def buildAnswers(answers: Seq[String]): Array[Answer] = {
-    val ans = new Array[Answer](answers.length)
+  private def buildAnswers(answers: Seq[String]): ArrayBuffer[Answer] = {
+    val ans = new ArrayBuffer[Answer]
     for (i <- 0 until answers.length) {
-      ans(i) = new Answer(i, answers(i), Some(answers(i)))
+      ans += new Answer(i, answers(i), Some(answers(i)))
     }
 
     ans
@@ -453,6 +481,16 @@ object PollFactory {
     questionOption
   }
 
+  private def processResponsePollType(qType: String): Option[Question] = {
+    var questionOption: Option[Question] = None
+
+    val answers = new ArrayBuffer[Answer]
+    val question = new Question(0, PollType.ResponsePollType, false, None, answers)
+    questionOption = Some(question)
+
+    questionOption
+  }
+
   private def createQuestion(qType: String, answers: Option[Seq[String]]): Option[Question] = {
 
     val qt = qType.toUpperCase()
@@ -468,6 +506,8 @@ object PollFactory {
       questionOption = processLetterPollType(qt, false)
     } else if (qt.startsWith(PollType.NumberPollType)) {
       questionOption = processNumberPollType(qt, false)
+    } else if (qt.startsWith(PollType.ResponsePollType)) {
+      questionOption = processResponsePollType(qt)
     }
 
     questionOption
@@ -530,6 +570,14 @@ class Poll(val id: String, val questions: Array[Question], val numRespondents: I
     })
   }
 
+  def addQuestionResponse(questionID: Int, answer: String) {
+    questions.foreach(q => {
+      if (q.id == questionID) {
+        q.addQuestionResponse(answer)
+      }
+    })
+  }
+
   def toPollVO(): PollVO = {
     val qvos = new ArrayBuffer[QuestionVO]
     questions.foreach(q => {
@@ -548,7 +596,10 @@ class Poll(val id: String, val questions: Array[Question], val numRespondents: I
   }
 }
 
-class Question(val id: Int, val questionType: String, val multiResponse: Boolean, val text: Option[String], val answers: Array[Answer]) {
+class Question(val id: Int, val questionType: String, val multiResponse: Boolean, val text: Option[String], val answers: ArrayBuffer[Answer]) {
+  def addAnswer(text: String) {
+    answers += new Answer(answers.size, text, Some(text))
+  }
 
   def clear() {
     answers.foreach(r => r.clear)
@@ -568,6 +619,10 @@ class Question(val id: Int, val questionType: String, val multiResponse: Boolean
     })
   }
 
+  def addQuestionResponse(answer: String) {
+    addAnswer(answer)
+  }
+
   def toQuestionVO(): QuestionVO = {
     val rvos = new ArrayBuffer[AnswerVO]
     answers.foreach(answer => {
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
index 683f07d0b0aabcd85962600150d2e8d9751bb5d4..40c6a169169f6584085951c241b75d29b0348b13 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/pubsub/senders/ReceivedJsonMsgHandlerActor.scala
@@ -117,6 +117,8 @@ class ReceivedJsonMsgHandlerActor(
         routeGenericMsg[GetCurrentPollReqMsg](envelope, jsonNode)
       case RespondToPollReqMsg.NAME =>
         routeGenericMsg[RespondToPollReqMsg](envelope, jsonNode)
+      case RespondToTypedPollReqMsg.NAME =>
+        routeGenericMsg[RespondToTypedPollReqMsg](envelope, jsonNode)
 
       // Webcam
       case UserBroadcastCamStartMsg.NAME =>
diff --git a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
index 8a1955c2e691dd618ca05957bee90d713673ab52..df25ea34720a879181ae87b1b182009e2d0ef245 100755
--- a/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
+++ b/akka-bbb-apps/src/main/scala/org/bigbluebutton/core/running/MeetingActor.scala
@@ -278,9 +278,9 @@ class MeetingActor(
 
   private def handleBbbCommonEnvCoreMsg(msg: BbbCommonEnvCoreMsg): Unit = {
     msg.core match {
-      case m: ClientToServerLatencyTracerMsg          => handleClientToServerLatencyTracerMsg(m)
+      case m: ClientToServerLatencyTracerMsg => handleClientToServerLatencyTracerMsg(m)
       case m: CheckRunningAndRecordingVoiceConfEvtMsg => handleCheckRunningAndRecordingVoiceConfEvtMsg(m)
-      case _                                          => handleMessageThatAffectsInactivity(msg)
+      case _ => handleMessageThatAffectsInactivity(msg)
     }
   }
 
@@ -297,7 +297,7 @@ class MeetingActor(
       case m: UserBroadcastCamStartMsg            => handleUserBroadcastCamStartMsg(m)
       case m: UserBroadcastCamStopMsg             => handleUserBroadcastCamStopMsg(m)
       case m: UserJoinedVoiceConfEvtMsg           => handleUserJoinedVoiceConfEvtMsg(m)
-      case m: LogoutAndEndMeetingCmdMsg => usersApp.handleLogoutAndEndMeetingCmdMsg(m, state)
+      case m: LogoutAndEndMeetingCmdMsg           => usersApp.handleLogoutAndEndMeetingCmdMsg(m, state)
       case m: SetRecordingStatusCmdMsg =>
         state = usersApp.handleSetRecordingStatusCmdMsg(m, state)
         updateUserLastActivity(m.body.setBy)
@@ -346,6 +346,9 @@ class MeetingActor(
       case m: RespondToPollReqMsg =>
         pollApp.handle(m, liveMeeting, msgBus)
         updateUserLastActivity(m.body.requesterId)
+      case m: RespondToTypedPollReqMsg =>
+        pollApp.handle(m, liveMeeting, msgBus)
+        updateUserLastActivity(m.body.requesterId)
 
       // Breakout
       case m: BreakoutRoomsListMsg            => state = handleBreakoutRoomsListMsg(m, state)
diff --git a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PollsMsgs.scala b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PollsMsgs.scala
index 6c641d61a2b54fee4f1d25e39c6e3688fbadc449..efc6c00880b011ad5eeb9596739cb8c94c4090e5 100755
--- a/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PollsMsgs.scala
+++ b/bbb-common-message/src/main/scala/org/bigbluebutton/common2/msgs/PollsMsgs.scala
@@ -16,7 +16,7 @@ case class PollShowResultEvtMsgBody(userId: String, pollId: String, poll: Simple
 
 object PollStartedEvtMsg { val NAME = "PollStartedEvtMsg" }
 case class PollStartedEvtMsg(header: BbbClientMsgHeader, body: PollStartedEvtMsgBody) extends BbbCoreMsg
-case class PollStartedEvtMsgBody(userId: String, pollId: String, poll: SimplePollOutVO)
+case class PollStartedEvtMsgBody(userId: String, pollId: String, pollType: String, question: String, poll: SimplePollOutVO)
 
 object PollStoppedEvtMsg { val NAME = "PollStoppedEvtMsg" }
 case class PollStoppedEvtMsg(header: BbbClientMsgHeader, body: PollStoppedEvtMsgBody) extends BbbCoreMsg
@@ -34,21 +34,29 @@ object RespondToPollReqMsg { val NAME = "RespondToPollReqMsg" }
 case class RespondToPollReqMsg(header: BbbClientMsgHeader, body: RespondToPollReqMsgBody) extends StandardMsg
 case class RespondToPollReqMsgBody(requesterId: String, pollId: String, questionId: Int, answerId: Int)
 
+object RespondToTypedPollReqMsg { val NAME = "RespondToTypedPollReqMsg" }
+case class RespondToTypedPollReqMsg(header: BbbClientMsgHeader, body: RespondToTypedPollReqMsgBody) extends StandardMsg
+case class RespondToTypedPollReqMsgBody(requesterId: String, pollId: String, questionId: Int, answer: String)
+
 object UserRespondedToPollRespMsg { val NAME = "UserRespondedToPollRespMsg" }
 case class UserRespondedToPollRespMsg(header: BbbClientMsgHeader, body: UserRespondedToPollRespMsgBody) extends BbbCoreMsg
 case class UserRespondedToPollRespMsgBody(pollId: String, userId: String, answerId: Int)
 
+object UserRespondedToTypedPollRespMsg { val NAME = "UserRespondedToTypedPollRespMsg" }
+case class UserRespondedToTypedPollRespMsg(header: BbbClientMsgHeader, body: UserRespondedToTypedPollRespMsgBody) extends BbbCoreMsg
+case class UserRespondedToTypedPollRespMsgBody(pollId: String, userId: String, answer: String)
+
 object ShowPollResultReqMsg { val NAME = "ShowPollResultReqMsg" }
 case class ShowPollResultReqMsg(header: BbbClientMsgHeader, body: ShowPollResultReqMsgBody) extends StandardMsg
 case class ShowPollResultReqMsgBody(requesterId: String, pollId: String)
 
 object StartCustomPollReqMsg { val NAME = "StartCustomPollReqMsg" }
 case class StartCustomPollReqMsg(header: BbbClientMsgHeader, body: StartCustomPollReqMsgBody) extends StandardMsg
-case class StartCustomPollReqMsgBody(requesterId: String, pollId: String, pollType: String, answers: Seq[String])
+case class StartCustomPollReqMsgBody(requesterId: String, pollId: String, pollType: String, answers: Seq[String], question: String)
 
 object StartPollReqMsg { val NAME = "StartPollReqMsg" }
 case class StartPollReqMsg(header: BbbClientMsgHeader, body: StartPollReqMsgBody) extends StandardMsg
-case class StartPollReqMsgBody(requesterId: String, pollId: String, pollType: String)
+case class StartPollReqMsgBody(requesterId: String, pollId: String, pollType: String, question: String)
 
 object StopPollReqMsg { val NAME = "StopPollReqMsg" }
 case class StopPollReqMsg(header: BbbClientMsgHeader, body: StopPollReqMsgBody) extends StandardMsg
diff --git a/bigbluebutton-html5/imports/api/polls/server/eventHandlers.js b/bigbluebutton-html5/imports/api/polls/server/eventHandlers.js
index a63a0e55bc8c49e520fce7699b350e0bf829adc2..13f8802f7c3cb65784e65462d124246626976f89 100644
--- a/bigbluebutton-html5/imports/api/polls/server/eventHandlers.js
+++ b/bigbluebutton-html5/imports/api/polls/server/eventHandlers.js
@@ -4,9 +4,11 @@ import handlePollStopped from './handlers/pollStopped';
 import handlePollPublished from './handlers/pollPublished';
 import handleUserVoted from './handlers/userVoted';
 import handleUserResponded from './handlers/userResponded';
+import handleUserTypedResponse from './handlers/userTypedResponse';
 
 RedisPubSub.on('PollShowResultEvtMsg', handlePollPublished);
 RedisPubSub.on('PollStartedEvtMsg', handlePollStarted);
 RedisPubSub.on('PollStoppedEvtMsg', handlePollStopped);
 RedisPubSub.on('PollUpdatedEvtMsg', handleUserVoted);
 RedisPubSub.on('UserRespondedToPollRespMsg', handleUserResponded);
+RedisPubSub.on('UserRespondedToTypedPollRespMsg', handleUserTypedResponse);
diff --git a/bigbluebutton-html5/imports/api/polls/server/handlers/pollStarted.js b/bigbluebutton-html5/imports/api/polls/server/handlers/pollStarted.js
index 013dba40879556eef379ff8ac3534fcebb19e97f..e1ad34f9c37b9d017bf06f868f56577ad5b844ff 100644
--- a/bigbluebutton-html5/imports/api/polls/server/handlers/pollStarted.js
+++ b/bigbluebutton-html5/imports/api/polls/server/handlers/pollStarted.js
@@ -3,14 +3,17 @@ import addPoll from '../modifiers/addPoll';
 import setPublishedPoll from '../../../meetings/server/modifiers/setPublishedPoll';
 
 export default function pollStarted({ body }, meetingId) {
-  const { userId } = body;
-  const { poll } = body;
+  const {
+    userId, poll, pollType, question,
+  } = body;
 
   check(meetingId, String);
   check(userId, String);
   check(poll, Object);
+  check(pollType, String);
+  check(question, String);
 
   setPublishedPoll(meetingId, false);
 
-  return addPoll(meetingId, userId, poll);
+  return addPoll(meetingId, userId, poll, pollType, question);
 }
diff --git a/bigbluebutton-html5/imports/api/polls/server/handlers/userTypedResponse.js b/bigbluebutton-html5/imports/api/polls/server/handlers/userTypedResponse.js
new file mode 100644
index 0000000000000000000000000000000000000000..eceb10dfbf74dac9623f8a32c6384907e33d485d
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/polls/server/handlers/userTypedResponse.js
@@ -0,0 +1,34 @@
+import { check } from 'meteor/check';
+import Polls from '/imports/api/polls';
+import RedisPubSub from '/imports/startup/server/redis';
+
+export default function userTypedResponse({ header, body }) {
+  const REDIS_CONFIG = Meteor.settings.private.redis;
+  const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
+  const EVENT_NAME = 'RespondToPollReqMsg';
+
+  const { pollId, userId, answer } = body;
+  const { meetingId } = header;
+
+  check(pollId, String);
+  check(meetingId, String);
+  check(userId, String);
+  check(answer, String);
+
+  const poll = Polls.findOne({ meetingId, id: pollId });
+
+  let answerId = 0;
+  poll.answers.forEach((a) => {
+    const { id, key } = a;
+    if (key === answer) answerId = id;
+  });
+
+  const payload = {
+    requesterId: userId,
+    pollId,
+    questionId: 0,
+    answerId,
+  };
+
+  return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, userId, payload);
+}
diff --git a/bigbluebutton-html5/imports/api/polls/server/methods.js b/bigbluebutton-html5/imports/api/polls/server/methods.js
index 5096ad7a7091a0fb527055f66285e0a3ce00bb31..57d7a08246127feef64c5a335ff4f1de46ffd2ac 100644
--- a/bigbluebutton-html5/imports/api/polls/server/methods.js
+++ b/bigbluebutton-html5/imports/api/polls/server/methods.js
@@ -1,4 +1,5 @@
 import { Meteor } from 'meteor/meteor';
+import publishTypedVote from './methods/publishTypedVote';
 import publishVote from './methods/publishVote';
 import publishPoll from './methods/publishPoll';
 import startPoll from './methods/startPoll';
@@ -6,6 +7,7 @@ import stopPoll from './methods/stopPoll';
 
 Meteor.methods({
   publishVote,
+  publishTypedVote,
   publishPoll,
   startPoll,
   stopPoll,
diff --git a/bigbluebutton-html5/imports/api/polls/server/methods/publishTypedVote.js b/bigbluebutton-html5/imports/api/polls/server/methods/publishTypedVote.js
new file mode 100644
index 0000000000000000000000000000000000000000..ffd29cc537f691ceccee1b84f8d0f7e0c5f92d42
--- /dev/null
+++ b/bigbluebutton-html5/imports/api/polls/server/methods/publishTypedVote.js
@@ -0,0 +1,53 @@
+import RedisPubSub from '/imports/startup/server/redis';
+import { check } from 'meteor/check';
+import Polls from '/imports/api/polls';
+import { extractCredentials } from '/imports/api/common/server/helpers';
+
+export default function publishTypedVote(id, pollAnswer) {
+  const REDIS_CONFIG = Meteor.settings.private.redis;
+  const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
+  let EVENT_NAME = 'RespondToTypedPollReqMsg';
+
+  const { meetingId, requesterUserId } = extractCredentials(this.userId);
+
+  check(pollAnswer, String);
+  check(id, String);
+
+  const activePoll = Polls.findOne({ meetingId, id }, {
+    fields: {
+      answers: 1,
+    },
+  });
+
+  let existingAnsId = null;
+  activePoll.answers.forEach((a) => {
+    if (a.key === pollAnswer) existingAnsId = a.id;
+  });
+
+  if (existingAnsId !== null) {
+    check(existingAnsId, Number);
+    EVENT_NAME = 'RespondToPollReqMsg';
+
+    return RedisPubSub.publishUserMessage(
+      CHANNEL,
+      EVENT_NAME,
+      meetingId,
+      requesterUserId,
+      {
+        requesterId: requesterUserId,
+        pollId: id,
+        questionId: 0,
+        answerId: existingAnsId,
+      },
+    );
+  }
+
+  const payload = {
+    requesterId: requesterUserId,
+    pollId: id,
+    questionId: 0,
+    answer: pollAnswer,
+  };
+
+  return RedisPubSub.publishUserMessage(CHANNEL, EVENT_NAME, meetingId, requesterUserId, payload);
+}
diff --git a/bigbluebutton-html5/imports/api/polls/server/methods/startPoll.js b/bigbluebutton-html5/imports/api/polls/server/methods/startPoll.js
index f6a08e3dd9045736783f28c8ef4ada7375048bbc..2fe305dd484f5eecb3dc4dae4e67141c25e33f58 100644
--- a/bigbluebutton-html5/imports/api/polls/server/methods/startPoll.js
+++ b/bigbluebutton-html5/imports/api/polls/server/methods/startPoll.js
@@ -2,7 +2,7 @@ import RedisPubSub from '/imports/startup/server/redis';
 import { check } from 'meteor/check';
 import { extractCredentials } from '/imports/api/common/server/helpers';
 
-export default function startPoll(pollType, pollId, answers) {
+export default function startPoll(pollType, pollId, question, answers) {
   const REDIS_CONFIG = Meteor.settings.private.redis;
   const CHANNEL = REDIS_CONFIG.channels.toAkkaApps;
 
@@ -17,6 +17,7 @@ export default function startPoll(pollType, pollId, answers) {
     requesterId: requesterUserId,
     pollId: `${pollId}/${new Date().getTime()}`,
     pollType,
+    question,
   };
 
   if (pollType === 'custom') {
diff --git a/bigbluebutton-html5/imports/api/polls/server/modifiers/addPoll.js b/bigbluebutton-html5/imports/api/polls/server/modifiers/addPoll.js
index 07d7457f552cc4505f9f2e3407699bf000db8fd5..df2d636081cbdea246cd6e444342c0c04e4f03f2 100644
--- a/bigbluebutton-html5/imports/api/polls/server/modifiers/addPoll.js
+++ b/bigbluebutton-html5/imports/api/polls/server/modifiers/addPoll.js
@@ -4,7 +4,7 @@ import Logger from '/imports/startup/server/logger';
 import flat from 'flat';
 import { check } from 'meteor/check';
 
-export default function addPoll(meetingId, requesterId, poll) {
+export default function addPoll(meetingId, requesterId, poll, pollType, question = '') {
   check(requesterId, String);
   check(meetingId, String);
   check(poll, {
@@ -37,6 +37,7 @@ export default function addPoll(meetingId, requesterId, poll) {
     { meetingId },
     { requester: requesterId },
     { users: userIds },
+    { question, pollType },
     flat(poll, { safe: true }),
   );
 
diff --git a/bigbluebutton-html5/imports/ui/components/poll/component.jsx b/bigbluebutton-html5/imports/ui/components/poll/component.jsx
index e99af79f1733ae3cf857796d493e1d51f1c6794e..17f09438d9bf63270a546c33291753c05e8e79ab 100644
--- a/bigbluebutton-html5/imports/ui/components/poll/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/poll/component.jsx
@@ -5,6 +5,7 @@ import PresentationUploaderContainer from '/imports/ui/components/presentation/p
 import { withModalMounter } from '/imports/ui/components/modal/service';
 import _ from 'lodash';
 import { Session } from 'meteor/session';
+import cx from 'classnames';
 import Button from '/imports/ui/components/button/component';
 import LiveResult from './live-result/component';
 import { styles } from './styles.scss';
@@ -62,25 +63,73 @@ const intlMessages = defineMessages({
     id: 'app.poll.tf',
     description: 'label for true / false poll',
   },
-  yn: {
-    id: 'app.poll.yn',
-    description: 'label for Yes / No poll',
-  },
-  a2: {
-    id: 'app.poll.a2',
-    description: 'label for A / B poll',
-  },
-  a3: {
-    id: 'app.poll.a3',
-    description: 'label for A / B / C poll',
-  },
   a4: {
     id: 'app.poll.a4',
     description: 'label for A / B / C / D poll',
   },
-  a5: {
-    id: 'app.poll.a5',
-    description: 'label for A / B / C / D / E poll',
+  delete: {
+    id: 'app.poll.optionDelete.label',
+    description: '',
+  },
+  pollPanelDesc: {
+    id: 'app.poll.panel.desc',
+    description: '',
+  },
+  questionLabel: {
+    id: 'app.poll.question.label',
+    description: '',
+  },
+  userResponse: {
+    id: 'app.poll.userResponse.label',
+    description: '',
+  },
+  responseChoices: {
+    id: 'app.poll.responseChoices.label',
+    description: '',
+  },
+  typedResponseDesc: {
+    id: 'app.poll.typedResponse.desc',
+    description: '',
+  },
+  responseTypesLabel: {
+    id: 'app.poll.responseTypes.label',
+    description: '',
+  },
+  addOptionLabel: {
+    id: 'app.poll.addItem.label',
+    description: '',
+  },
+  startPollLabel: {
+    id: 'app.poll.start.label',
+    description: '',
+  },
+  questionTitle: {
+    id: 'app.poll.question.title',
+    description: '',
+  },
+  true: {
+    id: 'app.poll.answer.true',
+    description: '',
+  },
+  false: {
+    id: 'app.poll.answer.false',
+    description: '',
+  },
+  a: {
+    id: 'app.poll.answer.a',
+    description: '',
+  },
+  b: {
+    id: 'app.poll.answer.b',
+    description: '',
+  },
+  c: {
+    id: 'app.poll.answer.c',
+    description: '',
+  },
+  d: {
+    id: 'app.poll.answer.d',
+    description: '',
   },
 });
 
@@ -93,19 +142,16 @@ class Poll extends Component {
     super(props);
 
     this.state = {
-      customPollReq: false,
       isPolling: false,
-      customPollValues: [],
+      question: '',
+      optList: [],
     };
 
-    this.inputEditor = [];
-
-    this.toggleCustomFields = this.toggleCustomFields.bind(this);
-    this.renderQuickPollBtns = this.renderQuickPollBtns.bind(this);
-    this.renderCustomView = this.renderCustomView.bind(this);
-    this.renderInputFields = this.renderInputFields.bind(this);
-    this.handleInputChange = this.handleInputChange.bind(this);
     this.handleBackClick = this.handleBackClick.bind(this);
+    this.handleAddOption = this.handleAddOption.bind(this);
+    this.handleRemoveOption = this.handleRemoveOption.bind(this);
+    this.handleTextareaChange = this.handleTextareaChange.bind(this);
+    this.handleInputChange = this.handleInputChange.bind(this);
   }
 
   componentDidMount() {
@@ -129,112 +175,105 @@ class Poll extends Component {
     }
   }
 
-  handleInputChange(index, event) {
-    // This regex will replace any instance of 2 or more consecutive white spaces
-    // with a single white space character.
-    const option = event.target.value.replace(/\s{2,}/g, ' ').trim();
-
-    this.inputEditor[index] = option === '' ? '' : option;
-
-    this.setState({ customPollValues: this.inputEditor });
-  }
-
   handleBackClick() {
     const { stopPoll } = this.props;
-    Session.set('resetPollPanel', false);
-
-    stopPoll();
-    this.inputEditor = [];
     this.setState({
       isPolling: false,
-      customPollValues: this.inputEditor,
-    }, document.activeElement.blur());
+    }, () => {
+      stopPoll();
+      Session.set('resetPollPanel', false);
+      document.activeElement.blur();
+    });
   }
 
-  toggleCustomFields() {
-    const { customPollReq } = this.state;
-    return this.setState({ customPollReq: !customPollReq });
+  handleInputChange(e, index) {
+    const { optList } = this.state;
+    const { value } = e.target;
+    const list = [...optList];
+    list[index] = { val: value };
+    this.setState({ optList: list });
   }
 
-  renderQuickPollBtns() {
-    const {
-      isMeteorConnected, pollTypes, startPoll, intl,
-    } = this.props;
-
-    const btns = pollTypes.map((type) => {
-      if (type === 'custom') return false;
-
-      const label = intl.formatMessage(
-        // regex removes the - to match the message id
-        intlMessages[type.replace(/-/g, '').toLowerCase()],
-      );
-
-      return (
-        <Button
-          disabled={!isMeteorConnected}
-          label={label}
-          color="default"
-          className={styles.pollBtn}
-          data-test="pollBtn"
-          key={_.uniqueId('quick-poll-')}
-          onClick={() => {
-            Session.set('pollInitiated', true);
-            this.setState({ isPolling: true }, () => startPoll(type));
-          }}
-        />);
-    });
+  handleTextareaChange(e) {
+    this.setState({ question: e.target.value });
+  }
 
-    return btns;
+  handleRemoveOption(index) {
+    const { optList } = this.state;
+    const list = [...optList];
+    list.splice(index, 1);
+    this.setState({ optList: list });
   }
 
-  renderCustomView() {
-    const { intl, startCustomPoll } = this.props;
-    const isDisabled = _.compact(this.inputEditor).length < 1;
+  handleAddOption() {
+    const { optList } = this.state;
+    this.setState({ optList: [...optList, { val: '' }] });
+  }
 
-    return (
-      <div className={styles.customInputWrapper}>
-        {this.renderInputFields()}
-        <Button
-          onClick={() => {
-            if (this.inputEditor.length > 0) {
-              Session.set('pollInitiated', true);
-              this.setState({ isPolling: true }, () => startCustomPoll('custom', _.compact(this.inputEditor)));
-            }
-          }}
-          label={intl.formatMessage(intlMessages.startCustomLabel)}
-          color="primary"
-          aria-disabled={isDisabled}
-          disabled={isDisabled}
-          className={styles.btn}
-        />
-      </div>
-    );
+  checkPollType() {
+    const { type, optList } = this.state;
+    let _type = type;
+    let pollString = '';
+    let defaultMatch = null;
+    let isDefault = null;
+
+    switch (_type) {
+      case 'A-':
+        pollString = optList.map(x => x.val).sort().join('');
+        defaultMatch = pollString.match(/^(ABCDEFG)|(ABCDEF)|(ABCDE)|(ABCD)|(ABC)|(AB)$/gi);
+        isDefault = defaultMatch && pollString.length === defaultMatch[0].length;
+        _type = isDefault ? `${_type}${defaultMatch[0].length}` : 'custom';
+        break;
+      case 'TF':
+        pollString = optList.map(x => x.val).join('');
+        defaultMatch = pollString.match(/^(TRUEFALSE)|(FALSETRUE)$/gi);
+        isDefault = defaultMatch && pollString.length === defaultMatch[0].length;
+        if (!isDefault) _type = 'custom';
+        break;
+      default:
+        break;
+    }
+    return _type;
   }
 
-  renderInputFields() {
+  renderInputs() {
     const { intl } = this.props;
-    const { customPollValues } = this.state;
-    let items = [];
-
-    items = _.range(1, MAX_CUSTOM_FIELDS + 1).map((ele, index) => {
-      const id = index;
+    const { optList } = this.state;
+    return optList.map((o, i) => {
+      const pollOptionKey = `poll-option-${i}`;
       return (
-        <div key={`custom-poll-${id}`} className={styles.pollInput}>
+        <div
+          key={pollOptionKey}
+          style={{
+            display: 'flex',
+            justifyContent: 'spaceBetween',
+            marginBottom: '1rem',
+          }}
+        >
           <input
-            aria-label={intl.formatMessage(
-              intlMessages.ariaInputCount, { 0: id + 1, 1: MAX_CUSTOM_FIELDS },
-            )}
+            type="text"
+            value={o.val}
             placeholder={intl.formatMessage(intlMessages.customPlaceholder)}
-            className={styles.input}
-            onChange={event => this.handleInputChange(id, event)}
-            defaultValue={customPollValues[id]}
+            className={styles.pollOption}
+            onChange={e => this.handleInputChange(e, i)}
             maxLength={MAX_INPUT_CHARS}
           />
+          { i > 1 ? (
+            <Button
+              className={styles.deleteBtn}
+              label={intl.formatMessage(intlMessages.delete)}
+              icon="delete"
+              hideLabel
+              circle
+              color="default"
+              onClick={() => {
+                this.handleRemoveOption(i);
+              }}
+            />) : <div style={{ width: '40px' }} />
+        }
         </div>
       );
     });
-
-    return items;
   }
 
   renderActivePollOptions() {
@@ -267,29 +306,143 @@ class Poll extends Component {
   }
 
   renderPollOptions() {
-    const { isMeteorConnected, intl } = this.props;
-    const { customPollReq } = this.state;
+    const { type, optList, question } = this.state;
+    const { startPoll, startCustomPoll, intl } = this.props;
+    const defaultPoll = type === 'TF' || type === 'A-';
+
+    let hasVal = false;
+    optList.forEach((o) => {
+      if (o.val.length > 0) hasVal = true;
+    });
+
+    const disableStartPoll = (type === 'RP' && question.length === 0) || (!hasVal && type !== 'RP');
 
     return (
       <div>
         <div className={styles.instructions}>
-          {intl.formatMessage(intlMessages.quickPollInstruction)}
+          {intl.formatMessage(intlMessages.pollPanelDesc)}
         </div>
-        <div className={styles.grid}>
-          {this.renderQuickPollBtns()}
+        <div>
+          <h4>{intl.formatMessage(intlMessages.questionTitle)}</h4>
+          <textarea
+            className={styles.pollQuestion}
+            value={question}
+            onChange={e => this.handleTextareaChange(e)}
+            rows="4"
+            cols="35"
+            placeholder={intl.formatMessage(intlMessages.questionLabel)}
+          />
         </div>
-        <div className={styles.instructions}>
-          {intl.formatMessage(intlMessages.customPollInstruction)}
+        <div>
+          <h4>{intl.formatMessage(intlMessages.responseTypesLabel)}</h4>
+          <div className={styles.responseType}>
+            <Button
+              label={intl.formatMessage(intlMessages.tf)}
+              color="default"
+              onClick={() => {
+                this.setState({
+                  type: 'TF',
+                  optList: [
+                    { val: intl.formatMessage(intlMessages.true) },
+                    { val: intl.formatMessage(intlMessages.false) },
+                  ],
+                });
+              }}
+              className={cx(styles.pBtn, { [styles.selectedBtn]: type === 'TF' })}
+            />
+            <Button
+              label={intl.formatMessage(intlMessages.a4)}
+              color="default"
+              onClick={() => {
+                this.setState({
+                  type: 'A-',
+                  optList: [
+                    { val: intl.formatMessage(intlMessages.a) },
+                    { val: intl.formatMessage(intlMessages.b) },
+                    { val: intl.formatMessage(intlMessages.c) },
+                    { val: intl.formatMessage(intlMessages.d) },
+                  ],
+                });
+              }}
+              className={cx(styles.pBtn, { [styles.selectedBtn]: type === 'A-' })}
+            />
+          </div>
+          <Button
+            label={intl.formatMessage(intlMessages.userResponse)}
+            color="default"
+            onClick={() => { this.setState({ type: 'RP' }); }}
+            className={cx(styles.pBtn, styles.fullWidth, { [styles.selectedBtn]: type === 'RP' })}
+          />
         </div>
-        <Button
-          disabled={!isMeteorConnected}
-          className={styles.customBtn}
-          color="default"
-          onClick={this.toggleCustomFields}
-          label={intl.formatMessage(intlMessages.customPollLabel)}
-          aria-expanded={customPollReq}
-        />
-        {!customPollReq ? null : this.renderCustomView()}
+        { type
+              && (
+              <div>
+                <h4>{intl.formatMessage(intlMessages.responseChoices)}</h4>
+                {
+                  type === 'RP'
+                    && (
+                    <div>
+                      <span>{intl.formatMessage(intlMessages.typedResponseDesc)}</span>
+                      <div className={styles.exampleResponse}>
+                        <div className={styles.exampleTitle} />
+                        <div className={styles.responseInput}>
+                          <div className={styles.rInput} />
+                        </div>
+                      </div>
+                    </div>
+                    )
+                }
+                {
+                  (defaultPoll || type === 'RP')
+                    && (
+                    <div style={{
+                      display: 'flex',
+                      flexFlow: 'column',
+                    }}
+                    >
+                      {defaultPoll && this.renderInputs()}
+                      {defaultPoll
+                        && (
+                        <Button
+                          className={styles.addItemBtn}
+                          label={intl.formatMessage(intlMessages.addOptionLabel)}
+                          color="default"
+                          icon="add"
+                          disabled={optList.length === MAX_CUSTOM_FIELDS}
+                          onClick={() => this.handleAddOption()}
+                        />
+                        )
+                      }
+                      <Button
+                        className={styles.startPollBtn}
+                        label={intl.formatMessage(intlMessages.startPollLabel)}
+                        disabled={disableStartPoll}
+                        color="primary"
+                        onClick={() => {
+                          this.setState({ isPolling: true }, () => {
+                            const verifiedPollType = this.checkPollType();
+                            const verifiedOptions = optList.map((o) => {
+                              if (o.val.length > 0) return o.val;
+                              return null;
+                            });
+                            if (verifiedPollType === 'custom') {
+                              startCustomPoll(
+                                verifiedPollType,
+                                question,
+                                _.compact(verifiedOptions),
+                              );
+                            } else {
+                              startPoll(verifiedPollType, question);
+                            }
+                          });
+                        }}
+                      />
+                    </div>
+                    )
+              }
+              </div>
+              )
+        }
       </div>
     );
   }
@@ -346,18 +499,13 @@ class Poll extends Component {
             icon="left_arrow"
             aria-label={intl.formatMessage(intlMessages.hidePollDesc)}
             className={styles.hideBtn}
-            onClick={() => {
-              Session.set('openPanel', 'userlist');
-            }}
+            onClick={() => { Session.set('openPanel', 'userlist'); }}
           />
-
           <Button
             label={intl.formatMessage(intlMessages.closeLabel)}
             aria-label={`${intl.formatMessage(intlMessages.closeLabel)} ${intl.formatMessage(intlMessages.pollPaneTitle)}`}
             onClick={() => {
-              if (currentPoll) {
-                stopPoll();
-              }
+              if (currentPoll) stopPoll();
               Session.set('openPanel', 'userlist');
               Session.set('forcePollOpen', false);
               Session.set('pollInitiated', false);
@@ -367,11 +515,8 @@ class Poll extends Component {
             size="sm"
             hideLabel
           />
-
         </header>
-        {
-          this.renderPollPanel()
-        }
+        {this.renderPollPanel()}
       </div>
     );
   }
diff --git a/bigbluebutton-html5/imports/ui/components/poll/container.jsx b/bigbluebutton-html5/imports/ui/components/poll/container.jsx
index ef3d4f003b84298dbaedec41d82b36e54a2a95c6..0a2833157a3cc2743c69decdf74598616dfe2900 100644
--- a/bigbluebutton-html5/imports/ui/components/poll/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/poll/container.jsx
@@ -22,9 +22,9 @@ export default withTracker(() => {
 
   const pollId = currentSlide ? currentSlide.id : PUBLIC_CHAT_KEY;
 
-  const startPoll = type => makeCall('startPoll', type, pollId);
+  const startPoll = (type, question = '') => makeCall('startPoll', type, pollId, question);
 
-  const startCustomPoll = (type, answers) => makeCall('startPoll', type, pollId, answers);
+  const startCustomPoll = (type, question = '', answers) => makeCall('startPoll', type, pollId, question, answers);
 
   const stopPoll = () => makeCall('stopPoll');
 
diff --git a/bigbluebutton-html5/imports/ui/components/poll/live-result/component.jsx b/bigbluebutton-html5/imports/ui/components/poll/live-result/component.jsx
index 0aa6f2ace9fb8bc84bb35c61ec1e8962807ad0b4..df12b2f498da69cf54af288d0fba50686436069b 100644
--- a/bigbluebutton-html5/imports/ui/components/poll/live-result/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/poll/live-result/component.jsx
@@ -186,7 +186,7 @@ class LiveResult extends PureComponent {
           {waiting
             ? <span className={styles.connectingAnimation} /> : null}
         </div>
-        {currentPoll
+        {currentPoll && currentPoll.answers.length > 0
           ? (
             <Button
               disabled={!isMeteorConnected}
diff --git a/bigbluebutton-html5/imports/ui/components/poll/styles.scss b/bigbluebutton-html5/imports/ui/components/poll/styles.scss
index f129c63e09414791a4900b495d34f6fde1788afe..4125467b183e2a0b3be2c4ea4c7d7ec75bf9a8a8 100644
--- a/bigbluebutton-html5/imports/ui/components/poll/styles.scss
+++ b/bigbluebutton-html5/imports/ui/components/poll/styles.scss
@@ -6,6 +6,8 @@
     --poll-column-amount: 2;
     --poll-blue: #1A73D4;
     --poll-header-offset: -0.875rem;
+    --poll-addItem-width: 6rem;
+    --poll-input-height: 2.5rem;
 }
 
 .closeBtn {
@@ -91,7 +93,6 @@
 }
 
 .instructions {
-    margin-top: var(--lg-padding-x);
     margin-bottom: var(--lg-padding-x);
     color: var(--color-text);
 }
@@ -120,7 +121,7 @@
 }
 
 .pollBtn:nth-child(odd) {
-    margin-right: var(--sm-padding-y);
+    margin-right: 1rem;
     margin-left: inherit;
 
     [dir="rtl"] & {
@@ -201,16 +202,143 @@
     font-size: var(--font-size-small);
     border: 1px solid var(--color-gray-lighter);
     border-radius: var(--border-radius);
-    padding: .3rem * 1 .3rem * 0.25;
-    padding-left: var(--lg-padding-y);
-
-    [dir="rtl"] & {
-    	padding: .3rem * 1 .3rem * 0.25;
-        padding-right:var(--lg-padding-y);
-    }
 }
 
 .noSlidePanelContainer {
     color: var(--color-gray-drak);
     text-align: center;
-}
\ No newline at end of file
+}
+
+.responseType {
+    display: flex;
+    justify-content: space-between;
+    position: relative;
+    width: 100%;
+    height: var(--poll-input-height);
+    margin-bottom: var(--lg-padding-x);
+
+    button {
+        position: relative;
+        width: 47%;
+    }
+}
+
+.fullWidth {
+    width: 100%;
+}
+
+.pollQuestion {
+    resize: none;
+}
+
+.pollOption {
+    margin-right: 1rem;
+
+    [dir="rtl"] & {
+        margin-right: 0;
+        margin-left: 1rem;
+    }
+}
+
+.pollQuestion,
+.pollOption {
+    @include inputFocus(var(--color-blue-light));
+
+    width: 100%;
+    color: var(--color-text);
+    -webkit-appearance: none;
+    padding: calc(var(--sm-padding-y) * 2) calc(var(--sm-padding-x) * 1);
+    border-radius: var(--border-radius);
+    font-size: var(--font-size-base);
+    border: 1px solid var(--color-gray-lighter);
+    box-shadow: 0 0 0 1px var(--color-gray-lighter);
+}
+
+.exampleTitle {
+    background-color: var(--color-gray-lightest);
+    height: var(--sm-padding-x);
+    border-radius:  var(--border-radius);
+    width: 75%;
+}
+
+.exampleResponse {
+    border: var(--color-gray-light) solid 1px;
+    border-radius:  var(--border-radius);
+    padding: 1rem;
+    margin-top: 1rem;
+
+    .responseInput {
+        border: var(--color-gray-light) solid 1px;
+        border-radius: var(--border-radius);
+        margin-top: 1rem;
+        height: var(--poll-input-height);
+        padding-top: var(--sm-padding-x);
+        padding-left: var(--sm-padding-x);
+        position: relative;
+    }
+}
+
+.rInput {
+    background-color: var(--color-gray-lightest);
+    height: var(--lg-padding-y);
+    border-radius: var(--border-radius);
+    width: 75%;  
+}
+
+.addItemBtn {
+    top: 1px;
+    position: relative;
+    display: block;
+    width: var(--poll-addItem-width);
+    padding-left: var(--md-padding-y);
+    padding-right: var(--md-padding-y);
+
+    &:hover {
+        span {
+            opacity: 1;
+        }
+    }
+}
+
+.startPollBtn {
+    position: relative;
+    width: 100%;
+    height: var(--poll-input-height);
+    margin-top: 1rem;
+
+    &:hover {
+        span {
+            opacity: 1;
+        }
+    }
+}
+
+.pBtn {
+    border: solid var(--color-gray-light) 1px;
+    height: var(--poll-input-height);
+    span {
+        &:hover {
+            opacity: 1;
+        }
+    }
+}
+
+.deleteBtn {
+    position: relative;
+    i {
+        font-size: 150%;
+    }
+}
+
+.selectedBtn {
+    background-color: var(--poll-blue);
+    color: var(--color-white);
+
+    &:hover,
+    &:focus,
+    &:active {
+        background-color: var(--poll-blue) !important;
+        box-shadow: none !important;
+        color: var(--color-white) !important;
+    }
+}
diff --git a/bigbluebutton-html5/imports/ui/components/polling/component.jsx b/bigbluebutton-html5/imports/ui/components/polling/component.jsx
index c0e7219a2e0c5d489de596adc565d91b9a585b99..e553ea4b15c13ab954ee829f9e69033cbb958e6e 100644
--- a/bigbluebutton-html5/imports/ui/components/polling/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/polling/component.jsx
@@ -16,12 +16,28 @@ const intlMessages = defineMessages({
   pollAnswerDesc: {
     id: 'app.polling.pollAnswerDesc',
   },
+  pollQestionTitle: {
+    id: 'app.polling.pollQestionTitle',
+  },
+  submitLabel: {
+    id: 'app.polling.submitLabel',
+  },
+  submitAriaLabel: {
+    id: 'app.polling.submitAriaLabel',
+  },
+  responsePlaceholder: {
+    id: 'app.polling.responsePlaceholder',
+  },
 });
 
 class Polling extends Component {
   constructor(props) {
     super(props);
 
+    this.state = {
+      typedAns: '',
+    };
+
     this.play = this.play.bind(this);
   }
 
@@ -40,9 +56,15 @@ class Polling extends Component {
       intl,
       poll,
       handleVote,
+      handleTypedVote,
       pollAnswerIds,
     } = this.props;
-    const { stackOptions, answers } = poll;
+
+    const {
+      typedAns,
+    } = this.state;
+
+    const { stackOptions, answers, question } = poll;
     const pollAnswerStyles = {
       [styles.pollingAnswers]: true,
       [styles.removeColumns]: answers.length === 1,
@@ -58,49 +80,88 @@ class Polling extends Component {
           })}
           role="alert"
         >
-          <div className={styles.pollingTitle}>
-            {intl.formatMessage(intlMessages.pollingTitleLabel)}
-          </div>
-          <div className={cx(pollAnswerStyles)}>
-            {poll.answers.map((pollAnswer) => {
-              const formattedMessageIndex = pollAnswer.key.toLowerCase();
-              let label = pollAnswer.key;
-              if (pollAnswerIds[formattedMessageIndex]) {
-                label = intl.formatMessage(pollAnswerIds[formattedMessageIndex]);
+          {question.length > 0 && (
+            <span className={styles.qHeader}>
+              <div className={styles.qTitle}>{intl.formatMessage(intlMessages.pollQestionTitle)}</div>
+              <div className={styles.qText}>{question}</div>
+            </span>)
+          }
+          { poll.pollType !== 'RP'
+            && (
+            <span>
+              {question.length === 0
+                && (
+                <div className={styles.pollingTitle}>
+                  {intl.formatMessage(intlMessages.pollingTitleLabel)}
+                </div>
+                )
               }
 
-              return (
-                <div
-                  key={pollAnswer.id}
-                  className={styles.pollButtonWrapper}
-                >
-                  <Button
-                    disabled={!isMeteorConnected}
-                    className={styles.pollingButton}
-                    color="primary"
-                    size="md"
-                    label={label}
-                    key={pollAnswer.key}
-                    onClick={() => handleVote(poll.pollId, pollAnswer)}
-                    aria-labelledby={`pollAnswerLabel${pollAnswer.key}`}
-                    aria-describedby={`pollAnswerDesc${pollAnswer.key}`}
-                  />
-                  <div
-                    className={styles.hidden}
-                    id={`pollAnswerLabel${pollAnswer.key}`}
-                  >
-                    {intl.formatMessage(intlMessages.pollAnswerLabel, { 0: label })}
-                  </div>
-                  <div
-                    className={styles.hidden}
-                    id={`pollAnswerDesc${pollAnswer.key}`}
-                  >
-                    {intl.formatMessage(intlMessages.pollAnswerDesc, { 0: label })}
-                  </div>
-                </div>
-              );
-            })}
-          </div>
+              <div className={cx(pollAnswerStyles)}>
+                {poll.answers.map((pollAnswer) => {
+                  const formattedMessageIndex = pollAnswer.key.toLowerCase();
+                  let label = pollAnswer.key;
+                  if (pollAnswerIds[formattedMessageIndex]) {
+                    label = intl.formatMessage(pollAnswerIds[formattedMessageIndex]);
+                  }
+
+                  return (
+                    <div
+                      key={pollAnswer.id}
+                      className={styles.pollButtonWrapper}
+                    >
+                      <Button
+                        disabled={!isMeteorConnected}
+                        className={styles.pollingButton}
+                        color="primary"
+                        size="md"
+                        label={label}
+                        key={pollAnswer.key}
+                        onClick={() => handleVote(poll.pollId, pollAnswer)}
+                        aria-labelledby={`pollAnswerLabel${pollAnswer.key}`}
+                        aria-describedby={`pollAnswerDesc${pollAnswer.key}`}
+                      />
+                      <div
+                        className={styles.hidden}
+                        id={`pollAnswerLabel${pollAnswer.key}`}
+                      >
+                        {intl.formatMessage(intlMessages.pollAnswerLabel, { 0: label })}
+                      </div>
+                      <div
+                        className={styles.hidden}
+                        id={`pollAnswerDesc${pollAnswer.key}`}
+                      >
+                        {intl.formatMessage(intlMessages.pollAnswerDesc, { 0: label })}
+                      </div>
+                    </div>
+                  );
+                })}
+              </div>
+            </span>
+            )
+          }
+          { poll.pollType === 'RP'
+            && (
+            <div className={styles.typedResponseWrapper}>
+              <input
+                onChange={e => this.setState({ typedAns: e.target.value })}
+                type="text"
+                className={styles.typedResponseInput}
+                placeholder={intl.formatMessage(intlMessages.responsePlaceholder)}
+              />
+              <Button
+                disabled={typedAns.length === 0}
+                color="primary"
+                size="sm"
+                label={intl.formatMessage(intlMessages.submitLabel)}
+                aria-label={intl.formatMessage(intlMessages.submitAriaLabel)}
+                onClick={() => {
+                  handleTypedVote(poll.pollId, typedAns);
+                }}
+              />
+            </div>
+            )
+          }
         </div>
       </div>);
   }
diff --git a/bigbluebutton-html5/imports/ui/components/polling/container.jsx b/bigbluebutton-html5/imports/ui/components/polling/container.jsx
index 92353cba9d5e26a57087191b0e1e17cfd0309377..14f8455ce8eea77aceea510d14fa40a01c894d68 100644
--- a/bigbluebutton-html5/imports/ui/components/polling/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/polling/container.jsx
@@ -16,6 +16,7 @@ const POLLING_ENABLED = Meteor.settings.public.poll.enabled;
 const PollingContainer = ({ pollExists, ...props }) => {
   const currentUser = Users.findOne({ userId: Auth.userID }, { fields: { presenter: 1 } });
   const showPolling = pollExists && !currentUser.presenter && POLLING_ENABLED;
+
   if (showPolling) {
     return (
       <PollingComponent {...props} />
@@ -27,10 +28,13 @@ const PollingContainer = ({ pollExists, ...props }) => {
 PollingContainer.propTypes = propTypes;
 
 export default withTracker(() => {
-  const { pollExists, handleVote, poll } = PollingService.mapPolls();
+  const {
+    pollExists, handleVote, poll, handleTypedVote,
+  } = PollingService.mapPolls();
   return ({
     pollExists,
     handleVote,
+    handleTypedVote,
     poll,
     pollAnswerIds: PollService.pollAnswerIds,
     isMeteorConnected: Meteor.status().connected,
diff --git a/bigbluebutton-html5/imports/ui/components/polling/service.js b/bigbluebutton-html5/imports/ui/components/polling/service.js
index 40c241ec099877c9d4f5019a707b307811ad0478..0a6accb7b8a5111acf10e0148b250c130cb533ba 100644
--- a/bigbluebutton-html5/imports/ui/components/polling/service.js
+++ b/bigbluebutton-html5/imports/ui/components/polling/service.js
@@ -26,13 +26,18 @@ const mapPolls = () => {
     poll: {
       answers: poll.answers,
       pollId: poll.id,
+      pollType: poll.pollType,
       stackOptions,
+      question: poll.question,
     },
     pollExists: true,
     amIRequester,
     handleVote(pollId, answerId) {
       makeCall('publishVote', pollId, answerId.id);
     },
+    handleTypedVote(pollId, answer) {
+      makeCall('publishTypedVote', pollId, answer);
+    },
   };
 };
 
diff --git a/bigbluebutton-html5/imports/ui/components/polling/styles.scss b/bigbluebutton-html5/imports/ui/components/polling/styles.scss
index 0e806213fc28fbe5d71c1b57541ed31a19af07d8..1fc1c873548d76362c039929834acc7e99c59a70 100644
--- a/bigbluebutton-html5/imports/ui/components/polling/styles.scss
+++ b/bigbluebutton-html5/imports/ui/components/polling/styles.scss
@@ -1,3 +1,4 @@
+@import "/imports/ui/stylesheets/mixins/focus";
 @import "../../stylesheets/variables/breakpoints";
 
 :root {
@@ -5,7 +6,7 @@
   --max-btn-width: 9em;
   --overlayIndex: 9999;
   --overlayOpacity: 0.349;
-  --pollIndex: 1016;
+  --poll-index: 1016;
   --poll-width: 18rem;
 }
 
@@ -27,7 +28,7 @@
   min-width: var(--poll-width);
   position: absolute;
 
-  z-index: var(--pollIndex);
+  z-index: var(--poll-index);
   border: 1px solid var(--color-off-white);
   border-radius: var(--border-radius);
   box-shadow: var(--color-gray-dark) 0px 0px var(--lg-padding-y);
@@ -58,10 +59,10 @@
 }
 
 .pollingTitle {
-  color: var(--color-text);
   white-space: nowrap;
   padding-bottom: var(--md-padding-y);
   padding-top: var(--md-padding-y);
+  font-size: var(--font-size-small);
 }
 
 .pollButtonWrapper {
@@ -124,3 +125,37 @@
 .hidden {
   display: none;
 }
+
+.qHeader {
+  text-align: left;
+  position: relative; 
+  left: var(--sm-padding-y);
+}
+
+.qTitle {
+  font-size: var(--font-size-small);
+}
+
+.qText {
+  color: var(--color-text);
+  word-break: break-word;
+  font-size: var(--font-size-large);
+}
+
+.typedResponseWrapper {
+  margin: var(--jumbo-padding-y) .5rem .5rem .5rem;
+  display: flex;
+  flex-flow: column;
+}
+
+.typedResponseInput {
+  @include inputFocus(var(--color-blue-light));
+  color: var(--color-text);
+  -webkit-appearance: none;
+  padding: calc(var(--sm-padding-y) * 2.5) calc(var(--sm-padding-x) * 1.25);
+  border-radius: var(--border-radius);
+  font-size: var(--font-size-base);
+  border: 1px solid var(--color-gray-lighter);
+  box-shadow: 0 0 0 1px var(--color-gray-lighter);
+  margin-bottom: 1rem;
+}
diff --git a/bigbluebutton-html5/private/locales/en.json b/bigbluebutton-html5/private/locales/en.json
index 783ad8410b59ae3ba1b6a75d084c7e033969403a..d82b03a01b23eb74509334ef4c423020ec874806 100755
--- a/bigbluebutton-html5/private/locales/en.json
+++ b/bigbluebutton-html5/private/locales/en.json
@@ -225,6 +225,16 @@
     "app.poll.customPlaceholder": "Add poll option",
     "app.poll.noPresentationSelected": "No presentation selected! Please select one.",
     "app.poll.clickHereToSelect": "Click here to select",
+    "app.poll.panel.desc" : "Fill out your polling details below.",
+    "app.poll.question.label" : "Write your question..",
+    "app.poll.userResponse.label" : "User Repsonse",
+    "app.poll.responseTypes.label" : "Response Types",
+    "app.poll.optionDelete.label" : "Delete",
+    "app.poll.responseChoices.label" : "Response Choices",
+    "app.poll.typedResponse.desc" : "Users will be presented with a text box to fill in their response.",
+    "app.poll.addItem.label" : "Add item",
+    "app.poll.question.title": "Ask a question",
+    "app.poll.start.label" : "Start Poll",
     "app.poll.t": "True",
     "app.poll.f": "False",
     "app.poll.tf": "True / False",
@@ -247,6 +257,10 @@
     "app.poll.liveResult.usersTitle": "Users",
     "app.poll.liveResult.responsesTitle": "Response",
     "app.polling.pollingTitle": "Polling options",
+    "app.polling.pollQestionTitle": "Polling Qestion",
+    "app.polling.submitLabel": "Submit",
+    "app.polling.submitAriaLabel": "Submit poll response",
+    "app.polling.responsePlaceholder": "Enter answer",
     "app.polling.pollAnswerLabel": "Poll answer {0}",
     "app.polling.pollAnswerDesc": "Select this option to vote for {0}",
     "app.failedMessage": "Apologies, trouble connecting to the server.",