ShinyEditor : Rich Text Editor in Shiny Apps

Deepanshu Bhalla 6 Comments , ,
Introduction
This post covers how you can implement HTML or Text Editor in a Shiny App. We are using open source TinyMCE javascript for text editor. It is one of the most popular text editor used by several famous blogs or websites. It allows several customization tools for styling such as font size and color, bullet and numbered list, table creation, alignment etc.
Use Cases for Online Text Editor
There are many scenarios where you need online text editor. Some of them are as follows -
  1. In the human resource management tool wherein you ask employees to submit their goals and write accomplishment and areas of improvement. Bullet and Numbered list are key formatting methods which would assist employees to list down their content. Employees can also copy content from MS Word and editor would preserve the formatting
  2. Suppose you are building a web app for customer feedback. You would allow customers to provide open-ended comments in the app. Rich Text Editor would help your users to describe their issues in clear manner.
  3. You write blogs and want HTML quickly for your (complete or partial) content. PS - I used it for this blog
HTML Editor in Shiny
Installation
I am glad to release R package named ShinyEditor for this. You can install it from github. It is not available in CRAN yet.
remotes::install_github("deepanshu88/ShinyEditor")

You also need an API key from Tiny website. You just need signup, it's absolutely free and straightforward to get an API. Once done, you will see API key. You also need to submit your domains where you want to deploy text editor. For example, if you want TinyMCE to implement on listendata.com, type that into the Domain name field and click Add domain. You can add more than one domain.

Demo
I deployed app on shinyapps.io. You can see demo here
HTML Editor in Shiny
Below is the simple example how you can use ShinyEditor package. Make sure to enter your API key here use_editor("API-Key") The following program would run even if you don't enter your API key but it throws an error message that your API key is incorrect.
library(shiny)
library(ShinyEditor)

# UI
ui <- fluidPage(

  # Setup
  use_editor("API-Key"),
  titlePanel("HTML Generator"),

  # Text Input 1
fluidRow(
  column(
    width = 6,
    editor('textcontent'),
    br(),
    actionButton(
      "generatehtml",
      "Generate HTML Code",
      icon = icon("code"),
      class = "btn-primary"
    )),

  column(
    width = 6,
    tags$pre(textOutput("rawText"))
  )
)

)

# Server
server <- function(input, output, session) {

  # Generate HTML
  observeEvent(input$generatehtml, {

    editorText(session, editorid = 'textcontent', outputid = 'mytext')

    output$rawText <- renderText({
      req(input$mytext)
      enc2utf8(input$mytext)
    })

  })

}

# Run App
shinyApp(ui = ui, server = server)
Options to customize Editor
In the editor( ) function you have parameter named options to customise editor. You can look at tinyMCE website to see the complete list of options permitted.

library(shiny)
library(ShinyEditor)

# UI
ui <- fluidPage(

  # Setup
  use_editor("API-Key"),
  titlePanel("HTML Generator"),

  # Text Input 1
  fluidRow(
    column(
      width = 6,
      editor('textcontent', text = "Sample Text",
      options = "branding: false,
             height: 300,
             plugins: ['lists', 'table', 'link', 'image', 'code'],
             toolbar1: 'bold italic forecolor backcolor | formatselect fontselect fontsizeselect | alignleft aligncenter alignright alignjustify',
             toolbar2: 'undo redo removeformat bullist numlist table blockquote code superscript  subscript strikethrough link image'"),
      br(),
      actionButton(
        "generatehtml",
        "Generate HTML Code",
        icon = icon("code"),
        class = "btn-primary"
      )),

    column(
      width = 6,
      tags$pre(textOutput("rawText"))
    )
  )

)

# Server
server <- function(input, output, session) {

  # Generate HTML
  observeEvent(input$generatehtml, {

    editorText(session, editorid = 'textcontent', outputid = 'mytext')

    output$rawText <- renderText({
      req(input$mytext)
      enc2utf8(input$mytext)
    })

  })

}

# Run App
shinyApp(ui = ui, server = server)

Print real-time HTML Conversion
Suppose you want to show real-time HTML of content written by user. In the program below, real-time HTML is shown in the right-hand sided box as soon as user enters some text in the editor.

library(shiny)
library(ShinyEditor)

# UI
ui <- fluidPage(
  
  # Setup
  use_editor("API-Key"),
  titlePanel("HTML Generator"),
  
  # Text Input 1
  fluidRow(
    column(
      width = 6,
      editor('textcontent')
      ),
    
    column(
      width = 6,
      tags$pre(textOutput("rawText"))
    )
  )
  
)

# Server
server <- function(input, output, session) {
  
  # Generate HTML
  values <- reactiveValues(a = NULL)
  
  observe({
    editorText(session, editorid = 'textcontent', outputid = 'mytext')
    req(input$mytext)
    values$a <- enc2utf8(input$mytext)
  })
  
    output$rawText <- renderText({
      req(values$a)
      values$a
    })
    

}

# Run App
shinyApp(ui = ui, server = server)


Update Editor
Package allows you to update editor on client side via UpdateEditor( ) function. See the complete example below.
 library(shiny)
 library(ShinyEditor)

 # UI
 ui <- fluidPage(

   # Setup
   use_editor("API-Key"),
   titlePanel("HTML Generator"),

   # Text Input 1
   fluidRow(
     column(
       width = 6,
       editor('textcontent'),
       br(),
       actionButton(
         "generatehtml",
         "Generate HTML Code",
         icon = icon("code"),
         class = "btn-primary"
       ), actionButton("updatedata", "Update Editor", icon = icon("edit"))),

     column(
       width = 6,
       tags$pre(textOutput("rawText"))
     )
   )

 )

 # Server
 server <- function(input, output, session) {

   # Generate HTML
   observeEvent(input$generatehtml, {

    editorText(session, editorid = 'textcontent', outputid = 'mytext')

     output$rawText <- renderText({
       req(input$mytext)
       enc2utf8(input$mytext)
     })

   })

   observeEvent(input$updatedata, {
    UpdateEditor(session,
                id = "textcontent",
                text = "<b>Sample Text</b>")

  })

 }

 # Run App
 shinyApp(ui = ui, server = server)
Related Posts
Spread the Word!
Share
About Author:
Deepanshu Bhalla

Deepanshu founded ListenData with a simple objective - Make analytics easy to understand and follow. He has over 10 years of experience in data science. During his tenure, he worked with global clients in various domains like Banking, Insurance, Private Equity, Telecom and HR.

6 Responses to "ShinyEditor : Rich Text Editor in Shiny Apps"
  1. I had my Tiny API Key and I used the command as the same as you guide, like this:
    use_editor("my_api_tiny_key")
    However, shiny App also display error:
    "This domain is not register with Tiny Cloud. Please review your appoved domain"
    I registered this API key for local host.
    Thanks so much

    ReplyDelete
    Replies
    1. It's so weird. Try with uploading it on shinyapps.io and register the API key for the same

      Delete
    2. Thanks a lot for replying my question, I will try it again.
      Thanks again,

      Delete
  2. Is there a way to save long (500-1000-word) inputs into an AWS S3 bucket?

    ReplyDelete
    Replies
    1. That's outside the scope of this package. Thanks!

      Delete
    2. Thanks for the prompt response! I see that in your server, you're saving it to value$a. Do you know the length or wordcount limitations saving it to a local object like this? Once it's saved in R I can easily send to AWS or whatever repository externally. I was typing in your demo, but didn't test there so I don't crash your shinyapps.io implementation. Thanks for the hard work on this!

      Delete
Next → ← Prev