Scalable Vector Graphics Form Field

I'm looking to enable user input in one of my SVG text fields when they click on it. Any ideas on how to achieve this?

     
           const wrapper = document.getElementById('wrapper');
           const text = document.getElementById('Username');
           
           const inputWrapper = document.getElementById('input-wrapper');
           const input = document.getElementById('input');
           const button = document.getElementById('button');
           
           
           text.addEventListener('click', () => {
              text.classList.toggle('hide');
              inputWrapper.classList.toggle('hide');
              input.focus();
           });
           
           button.addEventListener('click', () => {
              text.classList.toggle('hide');
              inputWrapper.classList.toggle('hide');
           });
           
           input.addEventListener('change', (e) => {
              text.innerText = e.target.value;
           });
         
            .cls-1 {
               clip-path: url(#clip-Login_page);
             }
       
             .cls-2 {
               opacity: 0.67;
               fill: url(#pattern);
             }
       
             .cls-3 {
               fill: #d9d9d9;
             }
       
             .cls-3, .cls-5 {
               stroke: #0d0d0d;
             }
       
             .cls-4 {
               fill: url(#pattern-2);
             }
       
             .cls-5 {
               fill: #f2f2f2;
             }
       
             .cls-6, .cls-7 {
               fill: #707070;
               font-family: Georgia;
             }
       
             .cls-6 {
               font-size: 25px;
             }
       
             .cls-7 {
               font-size: 20px;
             }
       
             .cls-8 {
               stroke: none;
             }
       
             .cls-9 {
               fill: none;
             }
       
             .cls-10 {
               fill: #fff;
             }
       
             .cls-11 {
               filter: url(#Rectangle_5);
             }
       
             .cls-12 {
               filter: url(#Amcan_logo);
             }
       
             .cls-13 {
               filter: url(#Rectangle_2);
             }
        
          .hide {
        display: none;
        }
     
   
          <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 375 667">
            <defs>
    
              <pattern id="pattern" preserveAspectRatio="none" width="100%" height="100%" viewBox="0 0 1920 1080">
                <image width="1920" height="1080" xlink:href="img/Amcan.gif"/>
              </pattern>
              <filter id="Rectangle_2" x="11" y="178" width="354" height="63" filterUnits="userSpaceOnUse">
                <feOffset dy="5" input="SourceAlpha"/>
                <feGaussianBlur stdDeviation="3" result="blur"/>
                <feFlood flood-opacity="0.161"/>
                <feComposite operator="in" in2="blur"/>
                <feComposite in="SourceGraphic"/>
              </filter>
              <pattern id="pattern-2" preserveAspectRatio="none" width="100%" height="100%" viewBox="0 0 593 186">
                <image width="593" height="186" xlink:href="img/Amcan_logo.png"/>
              </pattern>
              <filter id="Amcan_logo" x="13" y="28" width="349" height="123" filterUnits="userSpaceOnUse">
                <feOffset dy="10" input="SourceAlpha"/>
                <feGaussianBlur stdDeviation="3" result="blur-2"/>
                <feFlood flood-opacity="0.161"/>
                <feComposite operator="in" in2="blur-2"/>
                <feComposite in="SourceGraphic"/>
              </filter>
              <filter id="Rectangle_5" x="77" y="369" width="222" height="63" filterUnits="userSpaceOnUse">
                <feOffset dy="5" input="SourceAlpha"/>
                <feGaussianBlur stdDeviation="3" result="blur-3"/>
                <feFlood flood-opacity="0.161"/>
                <feComposite operator="in" in2="blur-3"/>
                <feComposite in="SourceGraphic"/>
              </filter>
              <clipPath id="clip-Login_page">
                <rect width="375" height="667"/>
              </clipPath>
            </defs>
          
            <g id="Login_page" data-name="Login page" class="cls-1">
              <rect class="cls-10" width="375" height="667"/>
              <rect id="Amcanerino" class="cls-2" width="510" height="667" transform="translate(-71)"/>
              <g class="cls-13" transform="matrix(1, 0, 0, 1, 0, 0)">
                <g id="Rectangle_2-2" data-name="Rectangle 2" class="cls-3" transform="translate(20 182)">
                  <rect class="cls-8" width="336" height="45"/>
                  <rect class="cls-9" x="0.5" y="0.5" width="335" height="44"/>
                </g>
              </g>
              <g class="cls-12" transform="matrix(1, 0, 0, 1, 0, 0)">
                <rect id="Amcan_logo-2" data-name="Amcan_logo" class="cls-4" width="331" height="104" transform="translate(22 28)"/>
              </g>
              <g id="Rectangle_3" data-name="Rectangle 3" class="cls-5" transform="translate(20 250)">
                <rect class="cls-8" width="336" height="45"/>
                <rect class="cls-9" x="0.5" y="0.5" width="335" height="44"/>
              </g>
              <g id="Rectangle_4" data-name="Rectangle 4" class="cls-5" transform="translate(20 311)">
                <rect class="cls-8" width="336" height="45"/>
                <rect class="cls-9" x="0.5" y="0.5" width="335" height="44"/>
              </g>
              <g class="cls-11" transform="matrix(1, 0, 0, 1, 0, 0)">
                <g id="Rectangle_5-2" data-name="Rectangle 5" class="cls-3" transform="translate(86 373)">
                  <rect class="cls-8" width="204" height="45"/>
                  <rect class="cls-9" x="0.5" y="0.5" width="203" height="44"/>
                </g>
              </g>
              <text id="SUBMIT" class="cls-6" transform="translate(139 405)"><tspan x="0" y="0">SUBMIT</tspan></text>
              <text id="Login" class="cls-6" transform="translate(156 214)"><tspan x="0" y="0">Login</tspan></text>
              
              <div id="wrapper">
                <text id="Username" class="cls-7" transform="translate(142 280)"><tspan x="0" y="0">Username</tspan></text>
                <div id="input-wrapper" class="hide">
                  <input id="input" type="text" value="Username"/>
                  <button id="button">Submit</button>
                </div>
              </div>
              <text id="Password" class="cls-7" transform="translate(145 341)"><tspan x="0" y="0">Password</tspan></text>
              </g>
            </svg>

This code has been updated based on Solo's recommendations.

Answer №1

<tspan> and <text> are not regular HTML elements; they are SVG elements with their own unique attributes. The attribute "contenteditable" does not apply to tspan (you can check by running

document.querySelector("#myTspan").isContentEditable
, which will return undefined).

However, tspan can inherit properties from its parent elements. So, if you have an inline SVG within an HTML file, wrapping the SVG in an editable element may work in some browsers, but it will make all text elements within the SVG editable.

<div contenteditable="true">
<svg>
<text id="Username" class="cls-7" transform="translate(142 20)"><tspan x="0" y="0">Username</tspan></text>
</svg>
</div>

In a standalone SVG file, the "contenteditable" attribute will not work as it is part of the HTML specification and not the SVG specification.

If you want to make the text editable in a standalone SVG, you will need to use a script as suggested in other answers. Make sure to read carefully about how to include JavaScript in SVG files: Including JavaScript in SVG

Answer №2

While you can't directly edit the text, there is a workaround by overlaying an input field on top of it. Check out the code snippet below:

.input-real {
  background: rgba(255, 255, 255, 0);
  color: transparent;
  padding: 0;
  border: 0 none transparent;
  line-height: 0;
}

.input-real:focus {
  background: rgba(255, 255, 255, 1);
  color: #333;
}

.input-real,
.input-mimic {
  font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
  font-size: 14px;
}
<svg viewBox="0 0 375 667">
  <text id="Username" class="input-mimic" x="50" y="50" alignment-baseline="hanging">Username</text>
  <foreignObject width="50" height="23" x="50" y="46">
    <input id="input" class="input-real" type="text" value="Username"/>
  </foreignObject>
</svg>

Answer №3

Implement contenteditable feature on tspan

For more information, visit - https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content

How does this functionality operate?

To enable editing, simply add the contenteditable attribute to almost any HTML element.

function toggleEdit() {
  var text = document.getElementById('Username');
  var tspan = text.firstElementChild;
  tspan.setAttribute('contenteditable', true);
}
<text id="Username" class="cls-7" transform="translate(142 280)"><tspan x="0" y="0">Username</tspan></text>
<div><button onclick="toggleEdit();">Edit input</button></div>

Answer №4

Big thanks for the assistance, everyone! I've learned that utilizing a JavaScript 'prompt' form can get the job done. It was as simple as adding this code:

<script>
function changeUsername()
{
document.getElementById('Username').textContent = prompt("Please enter your Username");
}
</script>

<rect onclick="changeUsername()" class="cls-8" width="336" height="45"/>

I had completely forgotten about the prompt form feature! Thanks once again to everyone who pitched in :)

Answer №5

You don't need to use jquery or JS, simply include the contenteditable="true" attribute on that text element and your task is complete...

<text contenteditable="true" id="Username" class="cls-7" transform="translate(142 280)"><tspan x="0" y="0">Username</tspan></text>

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

I am encountering issues with setting a background image in Bootstrap 3.1.1 while trying to achieve a par

I'm struggling to add a background image to my bootstrap site. I'm attempting to create a parallax site using stellar.js, and while the site is functional with text on each slide and correct scrolling links, the images just won't load. Despi ...

javascript accessing an external variable inside ajax function

I have implemented dajaxice to fetch a json attribute that I want to make global. However, I am facing an issue where my global variable is always showing up as "undefined": var recent_id; $(function(){ recent_id = Dajaxice.ticker.get_home_timeline(ge ...

What is the best way to use jQuery to update the color of an SVG shape?

Hello everyone! I'm excited to be a part of this community and looking forward to contributing in the future. But first, I could really use some assistance with what seems like a simple task! My focus has always been on web design, particularly HTML ...

Having trouble with my router in the express app - the .find and .findByID methods are not working properly. Also,

In my current setup with NextJS/MERN stack, I am using the server.js file in NextJS to import API routes and make API calls. The routes seem to be functioning properly as there is activity when calling them from Postman or the browser. However, it appears ...

Creating code that adheres to the ECMAScript 5 standards

In my quest to create a JavaScript library that adheres to modern standards such as HTML5, CSS3, and ESv5, I find myself wanting to break away from the mainstream libraries like jQuery and MooTools. While these are great tools, I believe in the importance ...

Traversing a nested array using jQuery

I'm attempting to utilize jQuery's each function in order to iterate through the provided array. My aim is to identify the key ("Name") and display its corresponding array values on the webpage. Array ( [E-mail] => Array ( ...

The children's className attribute can impact the parent element

As I work on creating a card object, I envision it with the className .card that is styled in CSS as follows: .card img{position:absolute; width:150px; height:160px} I want only the images inside my div to overlap each other while not affecting the divs ...

Modify the input value when using the get_search_form() function in Wordpress

After experimenting with the latest get_search_form() function in WordPress, I've encountered an issue where I can't figure out how to remove the text label from the search submit button. Does anyone have any suggestions or solutions for this pr ...

Display a div using data from a Model in MVC

I am working with a model List that has fields ContainerId (div id) and Code (HTML code), which I am passing to a Razor View. Can you suggest the most effective way to display the code from the model in the containerId? My initial thought is to utilize j ...

Different Techniques for Defining Functions in an AngularJS Controller Using the controllerAs Method

When using the 'controller as' approach instead of $scope, I am encountering issues with method calling from HTML. My question is, how many ways are there to declare and call functions using this approach? First: (For executing something initial ...

Run audio player in the background with Google Chrome Extension

I am working on an extension and I want to have a page with an audio player that continues to play even when I click outside of the extension. I tried using the "background" attribute in the manifest file, but it seems to only work with javascript files. ...

The Angular UI tree is malfunctioning on Mozilla Firefox

Check out this Plunker example. While this Plunker works well in Chrome and IE, it encounters issues in Mozilla Firefox. There seems to be a problem with the dropdown selection causing the page to reload. Any ideas on how to fix this? <script type= ...

JavaScript, detecting repeated characters

I need to create a script that checks an input box (password) for the occurrence of the same character appearing twice. This script should work alongside existing regex validation. I believe I will need to use a loop to check if any character appears twice ...

"Implementing a loading function on a particular div element within a loop using

Hey everyone! I'm new to this forum and have recently made the switch from jQuery to Vue.js - what a game-changer! However, I've hit a little snag. I need to set v-loading on multiple buttons in a loop and have it start showing when clicked. Her ...

Best practices for timeout in HTTP long polling

As an avid user of Javascript AJAX and long-polling, I am constantly seeking the best value for server response timeout. Despite scouring numerous documents, a detailed explanation for timeout continues to elude me. Some suggest 20 seconds, while others ...

Having trouble getting Javascript to reveal hidden elements based on their class

I am having some trouble making specific fields in a form appear based on the selection made from a dropdown menu. Below is a simplified snippet of my code, which should change the display from 'none' to 'block'. Can you help me figure ...

Difficulty in transferring JavaScript variable to PHP

After encountering a basic issue, I learned that PHP runs server-side and executes on pageload even if the include is nestled in an AJAX callback. Initially, I could display query results by returning PHP in the JavaScript value attribute, but failing to i ...

Issues with the HTML5 progress bar malfunctioning due to alterations made by Angular

Using the html5 progress bar <progress value="5" max="100"></progress> in angular can lead to it being replaced by angular classes. Angular also has its own progress bar that uses similar tags. However, elements like the html5 slider do not get ...

What is the process for creating a personalized user input in JavaScript?

When entering a tracking number, please ensure it follows this specific format: AB-CDEFG-H. The first character (A) must be a digit between 1 and 9 inclusive. The second character (B) should be an uppercase English letter. This is followed by a hyphen (-). ...

Step-by-step guide to swapping an element with a textarea element using javascript

My current project involves creating a user profile that includes a text box where users can describe themselves. I've already implemented a separate page for editing the profile, but now I want to add a feature where users can hover over their descri ...