8

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,988
  • 4
  • 24
  • 36

6 Answers6

7

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,484
  • 5
  • 48
  • 81
  • 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
  • 2
    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. – TheScrappyDev 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
5

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,377
  • 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
5

Use CSS Variables if possible

It's 2022 and there are simpler 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, do this:

.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
  • 9,708
  • 13
  • 64
  • 77
  • The only problem with this is browser support on [China mobile devices](https://caniuse.com/css-variables), where WeChat internal browser (QQ) does not still supports it. So if you're developing for non-China market, is great solution to go for. But if you need it to work in WeChat internal browser (Android devices), need to be aware of this issue. – Siniša Jul 30 '22 at 00:50
  • @Siniša this is true if you need to support extremely outdated browsers, but the question should also be asked of the business why you're still supporting these old browsers and how might you migrate users to more secure and modern browsers. https://caniuse.com/css-variables – maxshuty Jul 30 '22 at 11:23
  • Wish that was possible. If you develop for China market, there's no option to say "we don't support WeChat". No business for you if you do that. WeChat is used by probably 80% of advertising market for pushing html based campaigns (eg. mini web games, gamified experiences etc). Until Tencent updates their QQ browser (used by WeChat as internal browser, as a replacement to Chromium they used years ago). will need to deal with issues like this. – Siniša Aug 01 '22 at 05:24
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,853
  • 2
  • 24
  • 37
0

A quick oneliner, which dynamically appends a style tag to the body.

document.body.innerHTML += '<style>#foo:focus {background-color:gold}</style>'
<input id="foo"/>
-1

let input = document.querySelector(".input-text");
    let label = document.querySelector('.fields-label');
    input.addEventListener('focus', function(e){
        label.classList.add('is-active');
    })
    input.addEventListener('blur', function(e){
        if(input.value === "") {
            label.classList.remove('is-active');
        }
    })
     label.is-active{
            color:red;
        }
 
    <div class="input-fields">
        <label class="fields-label">Last Name</label>
        <input type="text" class="input-text">
    </div>

    
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 22 '22 at 23:22