Creating a TextArea with Javascript Validation leveraging CSS Pseudo Classes and Regex

I currently have a PHP/HTML form with input validation using HTML input patterns. To indicate that the entered input is correct, I utilize the CSS pseudo properties user-invalid/user-valid through a 'check_valid' class as shown below:

input.check_valid:user-invalid     { border: 4px dotted red;   }
input.check_valid:user-valid       { border: 4px solid  green; }

The issue arises with textareas due to the lack of pattern support. Although I have:

textarea.check_valid:user-invalid  { border: 4px dotted red;   }
textarea.check_valid:user-valid    { border: 4px solid  green; }

This only checks the minlength/maxlength of the textarea content and not the actual content itself.

Server-side validation (in PHP) successfully checks the textarea content, but I aim to implement a visual indication - a green/red border similar to the one for input fields when the content matches a specific regex pattern.

I am seeking a JavaScript snippet to emulate the behavior of check_valid:user-invalid/check_valid:user-valid when the user exits the textarea after entering content. This snippet should validate the content against a regex pattern (enabling pattern support for textareas).

Below is my incomplete attempt thus far:

const textArea1 = document.getElementById("textarea1");

textArea1.addEventListener("change", (event) => {
  let patternTextArea1 = /^[a-zA-Z0-9:\s,.'&()\/\-]{10,550}$/;
   
  if (// test textarea content against the regex) {
      // apply user-valid - green border
  } else {
      // apply user-invalid - red dotted line
  }
});

My JavaScript skills are lacking, as evident from the above code. I would greatly appreciate any assistance in solving this issue.

Answer №1

Implementing pattern validation for a textarea

While the textarea element itself does not support a pattern attribute, you can create one by utilizing a data attribute.

By incorporating a pattern check within the change event, you are able to validate the input and employ setCustomValidity to include a specific validation message.

The browser will handle the display of this custom message similarly to how it handles checks for minlength, maxlength, and required fields.

https://i.sstatic.net/r0VdyPkZ.png

Note: Pseudo classes like :invalid and :valid automatically trigger based on states. However, custom validation errors have a fixed language, unlike standard pattern errors. To implement internationalization would require additional coding (not demonstrated here).

Code Example The provided example is purposely simplistic to illustrate its functionality.

const textarea = document.querySelector('textarea')

textarea.addEventListener('input', () => {
  const reg = new RegExp(textarea.dataset.pattern, 'gmi');
  textarea.setCustomValidity('');
  if (!reg.test(textareavalue)) {
    textarea.setCustomValidity('Invalid characters detected in text field');
  }
  textarea.reportValidity(); // optional - displays an error popup
})
textarea {
  height: 2rem;
  padding: 0.5rem;
  border: 4px dotted black;
  outline: none;
}

textarea:valid {
  border-color: green;
}

textarea:invalid {
  border-color: red;
}

textarea:focus::placeholder {
  opacity: 0;
}
<textarea 
  required 
  minlength="10" 
  maxlength="500" 
  placeholder="enter text here"
  data-pattern="(?<!\n)^[()\w\s]+$(?!\n)">
</textarea>

Answer №2

Once the change event triggers on the textarea element, you have the ability to assign the same value to a hidden input element that includes the pattern attribute.

// Prevent the default invalid message from displaying
document.forms.form01.addEventListener('invalid', e => {
  e.preventDefault();
}, true);

document.forms.form01.addEventListener('change', e => {
  let form = e.target.form;
  if (e.target.dataset.name) {
    // Set the input field to match the value of the textarea
    form[e.target.dataset.name].value = e.target.value;
    // Apply appropriate class name based on validity
    e.target.classList.add('valid');
    if (!form[e.target.dataset.name].validity.valid) {
      e.target.classList.replace('valid', 'invalid');
    }
  }
});

document.forms.form01.addEventListener('submit', e => {
  e.preventDefault();
  let data = new FormData(e.target);
  console.log(...data);
});
form {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

textarea.invalid {
  border: 4px dotted red;
}

textarea.valid {
  border: 4px solid green;
}

input:user-invalid {
  border: 4px dotted red;
}

input:user-valid {
  border: 4px solid green;
}
<form name="form01">
  <input type="text" name="other" pattern=".{2,10}" required>
  <textarea data-name="longtext" name=""></textarea>
  <input type="text" name="longtext"
    pattern="[a-zA-Z0-9:\s,\.'&\(\)\/\-]{10,550}"
    style="display:none" required>
  <button type="submit">Submit</button>
</form>

Answer №3

Have you ever wondered how to ensure an element is either :user-valid or :user-invalid? Surprisingly, it is possible! By utilizing the

inputField.setCustomValidity(msg)
method, you can achieve this functionality. This approach technically targets :valid and :invalid, but with some CSS manipulation and the addition of a class called .user-interacted, you can specifically check for validity only when user interaction occurs.

Essentially, there are two key components here: using setCustomValidity and incorporating the .user-interacted class.

textarea.addEventListener("input", checkOnServer)

function checkOnServer(ev) {
  var elem = ev.target

  setTimeout(function() {
    // AJAX query to server
    elem.classList.add("user-interacted")
    var value = elem.value
    var msg = value.length > 3 ? '' : 'Length must be longer than 3 chars'
    elem.setCustomValidity(msg)
  }, 100)

}
textarea.check_valid.user-interacted:invalid {
  border: 4px dotted red;
}

textarea.check_valid.user-interacted:valid {
  border: 4px solid green;
}

textarea {
  outline: none;
}
<p>let's assume valid is > 3 chars</p>
<textarea id="textarea" class="check_valid" cols="80" rows="5"></textarea>

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

Issue with Bootstrap carousel - the carousel.on method is not recognized

I have implemented a standard Bootstrap carousel in my project: <div id="myCarousel" class="carousel slide" data-ride="carousel"> <ol class="carousel-indicators"> <li data-target="#myCarousel" data-slide-to="0" class="active"> ...

What is the best way to showcase a scope with a dropdown menu?

I'm a beginner in Angular and would appreciate constructive feedback. I am attempting to show specific text based on the option clicked in a dropdown button, but I can't seem to make it work. Can someone point out what's going wrong? Thank y ...

Tips for creating a form-flip, similar to a card-flip effect, using web technologies

Looking to create a card flip effect similar to the one shown here. Once the sign up process is finished, the card will smoothly flip over to reveal the other side with a transitioning effect. ...

I can't figure out why I keep receiving the InvalidArgumentError for H.Map with Argument #0 [object Object]

I recently refactored the code taken from the Maps API for JavaScript "Working with React" section. As a beginner in React and currently learning it in school, I have to utilize functional components. The material provided guidance on class component syn ...

Steps to display a div on top of a background image

Here is a visual representation of my design for better understanding: I am currently working on developing the central content that overlays the image. However, when I insert divs with background colors into my HTML to test their placement, I do not see ...

Is it possible to nest Route components in react-router version 4.x?

How can one properly implement nested routes in react-router version 4.x? Previous methods like the one below worked well, but upgrading to version 4.x now results in a warning... <Route path='/stuff' component={Stuff}> <Route path=&a ...

Combine several dictionary values under a single dictionary key in JavaScript

I have a unique dictionary structure displayed below. My goal is to populate it with values in a specific way. It all begins here var animals = { flying : {}, underground : {}, aquatic : {}, desert : {} }; To illustrat ...

JavaScript: Choosing between explicit imports and the * sign

Why do this in one way: import * as copy from 'copy-to-clipboard'; instead of the other way: import { someMethod } from 'copy-to-clipboard'; Does it impact performance or bundle size? Personally, I find the second option cleaner. ...

Have you ever encountered the orientationchange event in JavaScript before?

When does the orientationchange event trigger in relation to window rotation completion? Is there a way to fire an event before the operating system initiates the integrated window rotation? Edit: For example, can elements be faded out before the rotation ...

Access a component within an inactive carousel slide

I'm encountering a problem with the search feature in the carousel within my FAQ system. The search box is designed to locate questions within the FAQ list. Currently, when a user selects a question from the search results, they are redirected to th ...

Building hierarchical comments in React Native

I'm currently involved in a React Native project that includes a Nested comment section. These comments are retrieved as JSON data and displayed using a FlatList. const App = () => { const [isLoading, setLoading] = useState(true); const [data, ...

After resolving a promise, what is the process for loading a Next.js App?

Seeking guidance on implementing the code snippet below using Next.js. I suspect there is an issue with Next.js not being able to access the window object without being within a useEffect(() => {}) hook. When switching back to regular React, the code ...

eliminate gaps between hyperlinks using cascading style sheets

I developed a webapp for iOS which has a specific page containing a centered div with 3 buttons. Inside this div, there is a total of 460px with each link measuring as follows: the first and last are 153px while the middle one is 154px. The main issue ar ...

Choosing numerous items for carrying out a task

I am facing a challenge in selecting multiple items to delete records from the database. Although my delete.php script is functioning correctly, I am unable to implement the feature for deleting multiple selected items. I have added a checkbox but it is ...

React-Redux showing no errors despite non-functional Redux store

I'm currently facing an issue with integrating React-Redux into my React Native/Expo project. Despite not receiving any console error messages, the data from the Redux store is not displaying in the user interface. Below are some key files related to ...

Creating Custom Styles with Polymer for <content> Elements

Seeking help with styling using the ::content selector and custom CSS properties. Any insight would be appreciated! To simplify, I have a Polymer component utilizing a content tag that will always contain a paper-input: <template> <style> ...

Is it possible to assign a numerical value to the prev() function or the prevUntil() function in jQuery?

Is there a way to apply a specific style to the six previous and six next items of a list, while giving a different style to those outside of this range using only CSS? I am currently using a functional but redundant jQuery code for this purpose. Can the p ...

What could be causing my website to automatically adjust the CSS height on its own?

My code looks like this: <li style = "height: 250px;"> <p>Foo</p></li> Despite my efforts, when I visit the website, the height doesn't seem to change. After inspecting the element in Chrome, I discovered that it's s ...

I am facing an issue where my react app is only rendering in one file and not when imported into another

I've been diving into learning React and experimenting with building a simple app using the useState and useEffect hooks. However, I encountered an issue when exporting and importing my component from index.js to App.js file, and running ReactDOM.rend ...

Retrieve Files with Angular Framework

I'm looking to implement a file download or view button using Angular without making a call to the backend. The file is static and the same for all users, so I want to avoid unnecessary server requests. Many solutions involve using the "download" att ...