DEV Community

Cover image for Easy Inline CSS3 Lookups in JavaScript
Adam Nathaniel Davis
Adam Nathaniel Davis

Posted on • Edited on

Easy Inline CSS3 Lookups in JavaScript

[NOTE: Since writing this article, I've put this utility into an NPM package. You can find it here: https://www.npmjs.com/package/@toolz/css3]

When using JavaScript to do inline styling, you can run into several headaches:

  1. Unless you're a Certified CSS Guru, it can occasionally be difficult to remember all of the CSS3 properties that are available to you.

  2. And even if you remember all of the available properties, it can be even more daunting to remember all of the potential static values that are accepted on each of those properties.
    For example, if you want to set the cursor on a given element, there are dozens of potential values. Do you want move or grab? And are you sure you're not forgetting a more appropriate value that's available to you?

  3. Assuming that you know exactly which CSS3 property you want, and which value you want to assign to that property, you're still susceptible to spelling errors that could render your desired styling moot.
    For example, I've done this before: cursor : 'grabing'.

  4. Many of CSS's shorthand properties accept/require free-form text (e.g., the border property).
    But when you're writing your property, can you always, without fail, spit out the exact syntax that's required for that property?? For example, when writing margin : '10px 20px 30px 40px', is the top margin the second value? The third? It may feel old-hat to you now, but sometimes I still have to carefully read my style attributes to ensure that I haven't juxtaposed my values.

  5. Inline styles can leave you devoid of IDE assistance.
    If I'm writing a standalone .css file, my IDE does a pretty damn good job of showing me all of the available options in the autocomplete feature. But once I start using inline styles, the IDE can range from barely-helpful to downright useless.

This Is A Holy-War-Free Zone

Reading the "issues" I've outlined above, you may be sitting back and chortling while you think:

That's why you don't use inline styles!

So let's get one thing out of the way. Inline-vs-class CSS is definitely one of the coding/designing/HTML/CSS/JS Holy Wars. And I'm not writing this post to open that can of worms (I'll go there in another, future post...)

So if you're all smug in the knowledge that you simply do not use inline styles - in any scenario - then... this post is not for you. Seriously. I'd love to see you back on my blog at some future date. Maybe we can have a coffee sometime. But right now, for the rest of this post, we're gonna be catering to the slobbering coding masses who still, for whatever reason, find it appropriate to, at least occasionally, use inline styles.

Have a great day! Hope to see you around soon...

A Useful Little Helper Object

Alright... Are they gone???

Good. It was getting a little crowded in here anyway. Now that we've all got a bit more legroom, let me show you a simple helper object I've created to assist me in my dirty, grimy, inline CSS adventures.

The complete code for my utility can be found here:

https://github.com/bytebodger/javascript-css3-lookup

Don't be afraid. It's, literally, a single JavaScript file (not counting the README.md). That file's a bit long-ish (cuz it has references for basically all of the CSS3 properties and their accepted values). But there's no real logic in it.

Here's an abbreviated version of what that file contains:

const css3 = {
   background : {
      inherit : 'inherit',
      initial : 'initial',
      unset : 'unset',
      [`ex: url("bg.jpg") #fff`] : null,
      [`ex: url("bg.jpg") 20% 0% repeat-y fixed #fff`] : null,
      [`ex: url("bg.jpg") 20% 0% / contain repeat-y fixed content-box padding-box #fff`] : null,
   },
   dislay : {
      block : 'block',
      inherit : 'inherit',
      initial : 'initial',
      inline : 'inline',
      inlineBlock : 'inline-block',
      inlineTable : 'inline-table',
      listItem : 'list-item',
      none : 'none',
      table : 'table',
      tableCaption : 'table-caption',
      tableCell : 'table-cell',
      tableColumn : 'table-column',
      tableColumnGroup : 'table-column-group',
      tableFooterGroup : 'table-footer-group',
      tableHeaderGroup : 'table-header-group',
      tableRow : 'table-row',
      tableRowGroup : 'table-row-group',
      unset : 'unset',
   },
   textDecorationStyle : {
      dashed : 'dashed',
      dotted : 'dotted',
      double : 'double',
      inherit : 'inherit',
      initial : 'initial',
      solid : 'solid',
      unset : 'unset',
      wavy : 'wavy',
   },
};

export default css3;
Enter fullscreen mode Exit fullscreen mode

There's more - a lot more - in the full file. But the snippet above will be more than suitable to illustrate how this works. Now here's an example of how this file helps me in my daily coding:

import React from 'react';
import css3 from './css3';

export default class MyComponent extends React.Component {
   render = () => {
      return (
         <div>
            Inline styling is Da Bomb!
         </div>
      );
   };
}
Enter fullscreen mode Exit fullscreen mode

This is just a base React component, almost empty. And of course, our container <div> currently has no styling on it whatsoever. So let's do a little styling...

import React from 'react';
import css3 from './css3';

export default class MyComponent extends React.Component {
   render = () => {
      return (
         <div style={{
            textDecorationStyle : css3.  // Once I type the '.', my IDE springs into action.
         }}
         >
            Inline styling is Da Bomb!
         </div>
      );
   };
}
Enter fullscreen mode Exit fullscreen mode

As soon as I type css3., my IDE recognizes that I'm calling the css3 object and my autocomplete pops up with all the available properties on that object. Of course, textDecorationStyle is one of the properties on that object. So as soon as I type a few more letters, drilling down into t, then e, then x (etc.), my IDE quickly narrows down on the textDecorationStyle property.

That will eventually get me to here:

import React from 'react';
import css3 from './css3';

export default class MyComponent extends React.Component {
   render = () => {
      return (
         <div style={{
            textDecorationStyle : css3.textDecorationStyle.  // My IDE springs back into action!
         }}
         >
            Inline styling is Da Bomb!
         </div>
      );
   };
}
Enter fullscreen mode Exit fullscreen mode

Once it's clear that I've chosen the textDecorationStyle property, and I again type a ., my IDE's autocomplete pops up again. This time, it helpfully shows me all of the potential properties that exist on css3.textDecorationStyle.

I find this to be tremendously useful and time-saving. To be perfectly frank, even with 20+ of web development experience under my belt, I don't think I knew until today (!) that wavy was even an option on the textDecorationStyle CSS property. But with this little utility, I don't need to memorize all that minutiae. It's right there in front of me, staring at me from the autocomplete, any time I type css3.textDecorationStyle.

In the past, when I was thinking, "Hmm... this particular bit of text really needs to be styled differently," I would have had to reference the third lobe of my brain (a.k.a. Google). I woulda searched for "css text decoration style" and, in the worst-case scenario, I might have even felt compelled to browse through several sites looking for just the right option. And as powerful as Google/Stack Overflow/etc can be - they're also potential distractions. So anything that keeps my eyes in the code is a good thing.

When I'm done, the code looks like this:

import React from 'react';
import css3 from './css3';

export default class MyComponent extends React.Component {
   render = () => {
      return (
         <div style={{
            textDecorationStyle : css3.textDecorationStyle.wavy,
         }}
         >
            Inline styling is Da Bomb!
         </div>
      );
   };
}
Enter fullscreen mode Exit fullscreen mode

Sure, css3.textDecorationStyle.wavy is more verbose than just using 'wavy'. But the lookup process was swift. Any other developer looking at this code should be able to see, through nothing more than plain reading, what's happening. And I have the added bonus of knowing that it was impossible for me to misspell "wavy".

(If you think it's impractical to imagine that anyone could misspell "wavy", then congratulations. You're not old like me. You have the unbridled confidence of youth. Enjoy it. While it lasts...)

Also, if it's really bugging you to see that "long" css3.textDecoration.wavy value in the <div>'s style, you're always welcome to deconstruct it. In theory, after thorough deconstruction, you could end up with a line that looks like this:

textDecorationStyle : wavy,
Enter fullscreen mode Exit fullscreen mode

If I want to force my <div> to display inline, that would look like this:

import React from 'react';
import css3 from './css3';

export default class MyComponent extends React.Component {
   render = () => {
      return (
         <div style={{
            display: css3.display.inline,
            textDecorationStyle : css3.textDecorationStyle.wavy,
         }}
         >
            Inline styling is Da Bomb!
         </div>
      );
   };
}
Enter fullscreen mode Exit fullscreen mode

Finally, let's add a background to that <div>. This process will be a bit more... manual than the first two properties. Because the background property is a shorthand property. It allows us to chunk several different CSS values onto a single line.

Unfortunately, I know of no way to craft a helper object that will allow us to swiftly pick-and-choose the appropriate value for a shorthand property from a list. There are an infinite number of potential combinations. But even in that scenario, the css3 object can still provide us with some assistance.

When I go back into the React class and type:

background : css3.background.
Enter fullscreen mode Exit fullscreen mode

The autocomplete will, once again, spring into action. This time, it will only be able to give us suggestions. There are three standard properties under background: inherit, initial, and unset. But those are basically universal "default" properties that will do nothing to help me define the background the way I want.

But the css3 object does give us at least some "guidance" on typing the value. Right in the IDE's autocomplete function, there will be three "example" properties. Those properties aren't really meant to be chosen (which is why their values are set to null). But they do demonstrate the various syntaxes that are available to properly complete that value.

So after seeing these "helper syntaxes" in the css3 autocomplete options, I finish the demo component as such:

import React from 'react';
import css3 from './css3';

export default class MyComponent extends React.Component {
   render = () => {
      return (
         <div style={{
            background : 'url("someImage.png") repeat-y #ddd',
            display: css3.display.inline,
            textDecorationStyle : css3.textDecorationStyle.wavy,
         }}
         >
            Inline styling is Da Bomb!
         </div>
      );
   };
}
Enter fullscreen mode Exit fullscreen mode

And when I'm trying to crank out some React/Angular/JavaScript/whatever code, having that built-in utility helps me to avoid a lot of extraneous Googling.

Top comments (8)

Collapse
 
isaachagoel profile image
Isaac Hagoel

Cool writeup. It is similar to how we normally handle any other strings that need to be used in multiple places (theme related stuff, event names, enums etc.) - dy defining constants.

Some random thoughts:

  1. About the holy-wars, putting libraries like 'styled-components' asaide, inline-css is a must when assigning a dynamically calculated numeric values. For example, in the fancy drag and drop library the x and y transforms for the object being dragged and the objects that make room for it are all inlined.
  2. Bundle size will increase because of this. Sometimes it matters, sometimes not so much.
Collapse
 
bytebodger profile image
Adam Nathaniel Davis • Edited

Thanks again for the thoughtful feedback!

You're absolutely right that, when you boil it down, this is just a basic shared constant. I'm just amazed/annoyed sometimes when I realize that there are no "pre-baked" constants for the important shit that I find myself googling over and over and over...

  1. Totally agree about the inline-styling necessities (at times). I put that Holy War caveat in the article because, amongst some people, you simply cannot have an intelligent conversation about inline styles (especially, in React) without some pedantic jerk trying to shout you down. There's a whole other article on the horizon about this exact topic... One of my favorite (and simplest) justifications for inline React styles something like this: display : someCondition ? 'inherit' : 'none'. There's just no way that I'm gonna try to pack that away into two conditional CSS classes.

  2. Good point about bundle size. I will freely admit that, more often than not, I pay this little attention, because in today's high-bandwidth environment, I feel that this is usually a "micro-optimization". But that's not meant to discount your accurate observation. Like any other library/class/utility that is providing nothing more than syntactic convenience, it's always a good idea to at least be aware of the cost in package size.

Collapse
 
isaachagoel profile image
Isaac Hagoel

BTW, I do agree with the problem statement :)
I forgot to say in the original comment.
Remembering all of these css attributes and values and what they all do is like trying to memorize an encyclopedia.

Collapse
 
bytebodger profile image
Adam Nathaniel Davis

One more note on bundle size. If I were to put this into a proper NPM "package", I could create deploy hooks that would essentially empty out the lookup class and replace the code with the raw text/number values for the CSS properties. But, for the time being, that kinda feels like overkill and I don't have the time to dive into that...

Collapse
 
isaachagoel profile image
Isaac Hagoel

Another interesting option might be an IDE plug-in.
It could also maybe provide some documentation for each attribute/ value on the fly.
But yhea.. probably an overkill :)

Thread Thread
 
isaachagoel profile image
Isaac Hagoel
Thread Thread
 
bytebodger profile image
Adam Nathaniel Davis

Ideally, the plugin would be configurable, so you could drop in any object that would serve as a kinda "definition file". It could then be used in your autocompletes without needing to be bundled into the code itself.

It should be configurable, because even if this plugin worked beautifully, I'd hate to have to write another plugin (or find another one out there on the interwebs) the next time I have another set of commonly-used constants that I want to autocomplete.

Collapse
 
errorgamer2000 profile image
ErrorGamer2000

For the record, VS Code does this without the helper, thanks to React's type declarations.