7

I'm building a UI library in JS that can, without relying on any CSS stylesheets, create UI components, stylised from code. So far, it's been quite easy, with exception of styling different control states (such as input:focus one).

Code that I use to create input field:

function newInput()
{
    var ctr = docmuent.createElement("input");
    ctr.setAttribute("type","text");
    ctr.setAttribute("value", some-default-value);
    ctr.style.fontFamily = "sans-serif,helvetica,verdana";
    /* some font setup here, like color, bold etc... */
    ctr.style.width = "256px";
    ctr.style.height = "32px";
    return ctr;
}

Styling it for default state is easy. However I am unsure how to set style for states such as focused, disabled or not-editable.

If I'd be having CSS stylesheets included in the project that would be easily sorted out. However I can't have any CSS files included, it must be pure JS.

Does anyone know how to set style for an input field state (eg. input:focus) straight from JS code?

No JQuery please :-) Just straight-up JS.

Thanks in advance!

Siniša
  • 2,808
  • 4
  • 23
  • 35

4 Answers4

5

You would need to add an event listener to the element in order to change the style of it. Here is a very basic example.

var input = document.getElementById("something");
input.addEventListener("focus", function () {
  this.style.backgroundColor = "red";  
});
<input type="text" id="something" />
Cjmarkham
  • 9,057
  • 4
  • 47
  • 80
  • 2
    Did you mean: input.addEventListener? – Siniša Jan 03 '15 at 03:33
  • 1
    I may have meant that :P – Cjmarkham Jan 03 '15 at 03:55
  • Thanks. Both provided answers (the one below) give solution, but I can only accept one, and I've decided to go with yours since it avoids adding CSS in run-time to header. – Siniša Jan 04 '15 at 13:50
  • Unfortunately, this approach will not address the `focus` pseudo selector, but will instead update the background of the element when the `focus` event has been triggered. The only solution that will work here is @karthik's solution below, since it will allow selecting the `focus` pseudo selector. – FrostyDog Oct 18 '19 at 19:17
  • Both question and answer are nearly 5 years old. Let it rest in peace. I'm sure OP has found a better solution or abandoned the project in these years :) – Cjmarkham Oct 18 '19 at 21:13
3

Other alternative would be to build a stylesheet for the page.

Something like this:

 var styles='input:focus {background-color:red}';

 var styleTag=document.createElement('style');
 if (styleTag.styleSheet)
     styleTag.styleSheet.cssText=styles;
 else 
     styleTag.appendChild(document.createTextNode(styles));

 document.getElementsByTagName('head')[0].appendChild(styleTag);

This way you will have clean separation of css styles from the scripts and so the better maintenance.

Karthik
  • 1,357
  • 6
  • 8
  • Understood. However does this mean that it's set for all input fields that will be created? Is there a way to make style for each input field separately, in case there's need for different styling for each input field? – Siniša Jan 03 '15 at 03:45
  • you can change the css accordingly. you can go by element id or a class – Karthik Jan 03 '15 at 03:46
  • OK understood. Thanks. And when control is to be removed from UI, how can I remove it's style? So it won't pile up in the head. – Siniša Jan 03 '15 at 03:50
  • This approach helps you continue the typical dev cycle of writing html, scripts and css, where you update your css whenever the markup goes through the change. Since we don't have the luxury of CSS here, We could keep the JS code readable and maintenable as there is a separation in the styles and scripts. Infact you can put all the styles together in one file and have it included in the page. – Karthik Jan 03 '15 at 03:58
  • I agree that it's better to keep CSS and JS separated, but for this one client demands it all be in JS. Just to clarify, how can I then remove styleTag that is added to head using your approach, when control (input) is removed/disposed? – Siniša Jan 03 '15 at 04:22
  • Okay. What I would do is keep the CSS along with each control when it is built. For instance, I will have the addInput() method to have addInputStyles() in it. This way we will have better traction of links between the script and styles – Karthik Jan 03 '15 at 04:27
  • The code I posted was just an example how to build the css stylesheet with JS. You can break into pieces like different methods based on your css requirement and refer them accordingly when you build the dom elements – Karthik Jan 03 '15 at 04:30
  • Thanks. I wish I could accept both answers as they both give solution. I've decided to go with event handling only because I avoid adding CSS to header which my client may not approve (since it's been their request). But your approach also works, I'll upvote it. – Siniša Jan 04 '15 at 13:48
  • What is that `styleTag.styleSheet` property and why does it need to be checked? I couldn't find any information about that thing online. Is it dead and gone? Or new and stable now? – ygoe Apr 16 '21 at 17:38
1

At first, create your input:

<input type="text" id="myElementID" />

Then add the javascript the following javascript:

const element = document.getElementById("myElementID");

// Add a box shadow on focus
element.addEventListener("focus", (e) => {
  e.target.style.boxShadow = "0 0 0 3px #006bff40";
});

// Remove the box shadow when the user doesn't focus anymore
element.addEventListener("blur", (e) => {
  e.target.style.boxShadow = "";
});
JulienRioux
  • 2,360
  • 1
  • 19
  • 32
0

Use CSS Variables if possible

It's 2022 and there are more simple solutions to this problem than adding event listeners all over the place that may never get cleaned up.

Instead if you have control over the CSS simply do this in your CSS:

.my-class {
  --focusHeight: 32px;
  --focusWidth: 256px;
}

.my-class:focus {
  height: var(--focusHeight);
  width: var(--focusWidth);
}

Then in your JavaScript it's as simple as using setProperty to update the variables:

const el = document.getElementById('elementId');
el.style.setProperty('--focusHeight', newFocusHeight);
el.style.setProperty('--focusWidth', newFocusWidth);
maxshuty
  • 7,411
  • 9
  • 51
  • 69