Show the chosen option when the textarea is no longer in focus

My form includes a text box and a button:

<p><textarea rows="4" cols="30">Aliquam erat volutpat.</textarea></p>
<p><input type="button" value="Submit"></p>

When the user selects text in the textarea and then clicks on the submit button, the selection disappears once the textarea loses focus. Is there a way to keep the selected text visible? It doesn't need to be interactive (e.g., typing should not remove the selection or Ctrl+C to copy it), but I would like some visual indication that text is selected within the textarea.

Answer №1

Delving into jsFiddle, I came across CodeMirror, a tool that provides all the necessary elements to create a highly personalized textarea. Although primarily designed for coding, with a simple trick it can be adapted for general textareas as well.

Take a look at the DEMO

To start off, set up a textarea:

<textarea id="a">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</textarea>

Next, add the following script below it to transform the textarea into a CodeMirror textarea and apply extra configurations to revert it back to a regular textarea.

  • mode: In this case, I'm using "none" to eliminate syntax highlighting.
  • lineWrapping: Set it to true for automatic line wrapping on long lines.
var myCodeMirror = CodeMirror.fromTextArea(document.getElementById("a"), {
    mode: "none",
    lineWrapping: true
});

Lastly, employ CSS to adjust the dimensions and mimic the appearance of a standard textarea:

.CodeMirror {
    font-family: monospace;
    font-size: 12px;
    width: 300px;
    height: 100px;
    border: solid 1px #000;
}

Answer №2

<textarea onblur="this.focus()">this is a test</textarea>
<p><input type="button" value="Click me"></p>

Functioning properly in IE and Chrome, but not in FF.


Here's a universal fix:

<textarea onblur="doBlur(this)">this is a test</textarea>
<p><input type="button" value="Click me"></p>

<script>
function doBlur(obj) {
  setTimeout(function() { obj.focus(); }, 10);
}
</script>

Answer №3

Although this might not be exactly what you were looking for, I'm going to take a shortcut.

Javascript:

var textarea = document.getElementById('textarea');
var div = document.getElementById('holder');

var original_value = textarea.value;
textarea.onblur = function () {
    var start = textarea.selectionStart;
    var end = textarea.selectionEnd;
    textarea.style.display = "none";
    div.innerHTML = textarea.value.splice(end, 0, "</span>").splice(start, 0, "<span>");
    div.style.display = "block";
}

div.onclick = function () {
    div.style.display = "none";
    textarea.style.display = "block";
    textarea.value = original_value;
}

String.prototype.splice = function( idx, rem, s ) {
    return (this.slice(0,idx) + s + this.slice(idx + Math.abs(rem)));
};

HTML:

<p><textarea id="textarea" rows="4" cols="30">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</textarea></p>
<div id="holder"></div>
<p><input id="click" type="button" value="Click me"></p>

CSS:

textarea, #holder{
    height: 120px;
    width: 300px;
    border: 1px solid black;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    padding: 3px;
    font-size: 10pt;
    font-family: Arial;
}
#holder{    
    display: none;
}
#holder span{
    background-color: #b4d5ff;
}

demo: http://jsfiddle.net/Mb89X/4/

Answer №4

You may consider enclosing the textarea in an iframe, allowing the selection to still be visible within the frame upon clicking the button.

This particular demonstration makes use of the srcdoc attribute, which is only compatible with Chrome and Safari 6. However, you can opt for using an iframe without relying on that attribute.

UPDATE: Check out this alternative fiddle that employs jQuery to insert the iframe; it functions effectively in Chrome and Firefox (since Internet Explorer restricts data URIs in an iframe due to security concerns).

Answer №5

It is not achievable with a textarea to accomplish what you are attempting.

Instead of utilizing a textarea, my recommendation would be to use a div with contenteditable="true" along with rangy. Then you can wrap the selected text or choose the text during focus and blur events.

This rangy demo illustrates how to select text:

Answer №6

Given inspiration from @Prisoner, my goal is to enhance the functionality until it seamlessly integrates with scrolling and resizing.

The core concept remains unchanged. I have also developed a comprehensive demonstration with annotations here. Below is a repost for the context of this discussion.

var input = document.getElementById('input');
var div = document.getElementById('holder');

function synchronizeSize() {
    div.style.width = (input.scrollWidth - 4) + "px";
    div.style.height = input.style.height;
}

new MutationObserver(synchronizeSize).observe(input, {
    attributes: true,
    attributeFilter: ["style"]
});

synchronizeSize();

input.onchange = () => synchronizeSize();

input.onblur = () => {
    var start = input.selectionStart;
    var end = input.selectionEnd;
    var text = input.value;
    div.innerHTML = text.substring(0, start) +
        "<span>" + text.substring(start, end) +
        "</span>" + text.substring(end);
    div.style.display = "block";
}

input.onfocus = () => div.style.display = "none";

input.onscroll = () => div.style.top = -input.scrollTop + "px";

input.value = "Lorem ipsum dolor sit amet";

input.select();
#container {
  position: relative; 
  overflow: hidden;
}

#input {
  width: 400px;
  height: 150px;
}

#holder, #input {
    padding: 2px;
    font: 400 13.3333px monospace;
    border: 1px solid #a9a9a9;
    white-space: pre-wrap;
    word-wrap: break-word;
}

#holder {
    display: none;
    position: absolute;
    left: 0;
    top: 0;
    color: transparent;
    pointer-events: none;
    border-color: transparent;
}

#holder span {
    background-color: #c8c8c8;
    color: black;
}
<div id="container">
  <textarea id="input"></textarea>
  <div id="holder"></div>
</div>

Answer №7

In case the button's :focus is not important, this alternative can be considered:

$('input[type=button]').click(function () {
    $('textarea').focus();
});

You can find a working example on this link.

Answer №8

Give this a shot:

const textElement = document.getElementById('text');
if (textElement.setSelectionRange) {
    textElement.focus();
    textElement.setSelectionRange(2, 10);    
} else if (textElement.createTextRange) {
    const selRange = textElement.createTextRange();
    selRange.collapse(true);
    selRange.moveStart('character', 2);
    selRange.moveEnd('character', 10);
    selRange.select();
    textElement.focus();
} else if (typeof textElement.selectionStart !== 'undefined') {
    textElement.selectionStart = 2;
    textElement.selectionEnd = 10;
    textElement.focus();
}

Check it out here!

Answer №9

Developed a custom jQuery plugin that enhances a specified <textarea> element by adding a subtle grayed out selection when the element is not in focus.

// Created a jQuery plugin to enhance visibility of textarea selection when unfocused.                                                                                                                        
// This is achieved by overlaying the selected text with <mark> tags within an underlay                                                                                                                       
$.fn.selectionShadow = function () {
  const $input = this
  const prop = n => parseInt($input.css(n))
  const $wrap = $input.wrap('<div>').parent()   // wrapper                                                                                                                                               
    .css({
      ...Object.fromEntries(
        'display width height font background resize margin overflowWrap'
          .split(' ').map(x => [x, $input.css(x)])),
      position: 'relative',
      overflow: 'hidden',
      border: 0,
      padding: ['top', 'right', 'bottom', 'left'].map(
        x => prop(`padding-${x}`) + prop(`border-${x}-width`) + 'px'
      ).join(' '),
    })
  const $shadow = $('<span>').prependTo($wrap)  // shadow-selection                                                                                                                                      
    .css({ color: 'transparent' })
  $input                                        // input element                                                                                                                                         
    .on('focusin',  () => $shadow.hide())       //   hide shadow if focused                                                                                                                              
    .on('focusout', () => $shadow.show())
    .on('select', evt => {                      //   if selection change                                                                                                                                 
      const i = evt.target                      //     update shadow                                                                                                                                     
      const [x, s, a] = [i.value ?? '', i.selectionStart, i.selectionEnd]
      $shadow.html(x.slice(0, s) + '<mark class=selectionShadow>' +
                   x.slice(s, a) + '</mark>' + x.slice(a))
    })
    .css({
      boxSizing: 'border-box',
      position: 'absolute', top: 0, left: 0, bottom: 0, right: 0,
      overflow: 'hidden',
      display: 'block',
      background: 'transparent',
      resize: 'none',
      margin: 0,
    })
  $('head').append(
    `<style>mark.selectionShadow { background: #0003; color: transparent }`)
}

To activate the plugin, use $('textarea').selectionShadow().

The plugin adds an 'underlay' layer to the textarea and ensures it matches the padding, font style, and word wrapping settings. This way, the textarea and underlay text align perfectly. The underlay updates alongside the textarea's selection, highlighting the current selection using <mark> tags with a gray background (text color set to transparent to avoid interference with text edges).

This implementation was crafted for personal web projects, feel free to utilize!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating custom ExpectedConditions with Protractor for detecting attribute changes

I've been working on creating a custom ExpectedConditions method that can wait for an element attribute to change. Here is the approach I came up with: const CustomExpectedCondition = function() { /** * Check if element's attribute matches ...

Creating interactive JSON objects through the use of JavaScript and AngularJS

When using AngularJS to build a dynamic JSON from server data, I encountered an issue where my current declaration only works if the server data contains one item in the object array. How can I modify this to handle multiple items dynamically? $scope.it ...

What is the best way to renew an access token with axios?

I have been struggling to understand the concept of refreshing tokens after reading numerous articles on the topic. They all seem too convoluted for me to grasp. Could someone please simplify it for me? Here is an overview of what I am trying to achieve: ...

The ReactJS code encountered an error when attempting to access the 'location' property of an undefined or null reference

My Reactapp is encountering an error due to a specific file. import React from 'react'; import { Router, Route } from 'react-router'; import App from './components/App'; import About from './components/About'; im ...

choose a unique jQuery id without any duplicates

Trying to implement a simple system comment feature similar to Facebook, but struggling with selecting the right ID for submission. The issue I'm facing is that the first form works correctly, but for subsequent forms, I always retrieve the data-id fr ...

Displaying incorrect text format on a TextView using Html.fromHtml()

Within my application, there is a string that represents a mathematical expression: String s = "log<small><sub>(log<small><sub>(log<small><sub>3<small><sup>2</sup></small></sub></small&g ...

Tips for updating an element in an array by using another element from a separate array

What is the objective? We have two arrays: orders and NewOrders We need to check for any orders with the same order_id in both arrays. If there is a match, we then compare the order status. If the order from the NewOrders array has a different status, w ...

The flask application encounters a 404 error when trying to access the favicon.ico file

Upon reviewing my logfile, I noticed numerous entries indicating attempts to load files like /favicon.ico GET - /favicon.ico GET - /apple-touch-icon.png GET - /apple-touch-icon-precomposed.png I have researched this issue extensively online, but have bee ...

Executing a C# method from within a .js file using a Javascript function in a .cs file

I've made some updates based on the responses provided. My main area of confusion lies in the 'data' parameter and how to handle it in the JavaScript call. C# method [HttpPost] public string GetPreviewURL(string activityID) ...

Steps for sending a POST request for every file in the given array

I am working on an angular component that contains an array of drag'n'dropped files. My goal is to make a POST request to http://some.url for each file in the array. Here is what I have been attempting: drop.component.ts public drop(event) { ...

Updating Vue component with mismatched props

I am looking to optimize the Vue component where data is received in varying structures. Take for example Appointment.vue component: <template> <div> <div v-if="config.data.user.user_id"> {{ config.data.user.user_id ...

Tips for fixing the error message "Unhandled Promise Rejection: TypeError: response.body.forEach is not a function" in Vue.js 2

Here is how my Vue.js component looks: <script> export default{ name: 'CategoryBsSelect', template: '\ <select class="form-control" v-model="selected" required>\ <option v-for="option in opt ...

Designing a rounded border radius for various child elements within a layout

I am currently working on creating a circular container that houses an image and a description overlaid at 50% opacity. Here is what I have achieved so far: https://i.stack.imgur.com/pIkO1.png My goal is to apply a uniform border-radius to the entire div ...

The timeouts persist in firing and running even after being cleared and the component has been unmounted

I am currently working on creating bus animations based on an array of coordinates. I am using setTimeout to trigger a function that moves the marker to the next coordinate. However, I am facing an issue where the functions continue to execute even after c ...

Using the codesnippet feature in CKEditor in combination with highlight.js

I am currently experimenting with implementing the highlight.js library in conjunction with the CKEditor addon called CodeSnippet. Although I have successfully integrated the CodeSnippet addon into my CKEditor, the code is not being properly detected, col ...

The fetching of data with getJSON through an IP address is experiencing technical

Here's the issue I'm facing: Whenever I make a json call using the code below var url="http://localhost:9000/json"; $.getJSON(url, function(data){ alert(data['yay']); }); It works perfectly fine. However, my localhost IP is ...

Utilizing ng-repeat $index for locating an element within an array

Within my $scope, there is a property called $scope.cars, which is an array of cars. Users have the ability to delete a car from this array. When calling the delete function deleteThis, I pass the $index parameter created by ng-repeat. However, in the Ja ...

Setting up Webpack for react-pdf in a Next.js application

In my Next.js application, I am utilizing the react-pdf library to generate and handle PDF files on the client side without involving the server. However, I am facing challenges in setting up Webpack for Next.js as I lack sufficient expertise in this area. ...

The JavaScript function's if and else statements are being executed simultaneously

Upon loading the page, I am checking the value of a dropdown. Strangely, when I debug, it appears that the controller is executing both the if and else statements, which should not be happening. /* Here is my code: */ $(window).load(function() { ...

Transform them into async/await in JavaScript

Exploring the promise-retry library, I discovered the following syntax: promiseRetry(function (retry, number) { return doSomething() .catch(retry); }) .then(function (value) { // .. }, function (err) { // .. }); Since I am utilizing a ...