DNN Blogs

Written for the Community, by the Community

Creating DNN Themes With Tailwind CSS - Part 1

Written By Steve Krantzman
2020-08-18

In this two-part series, I will discuss creating DNN Themes utilizing the Tailwind CSS framework. It was meant to be a single blog post to introduce you to a new theme development platform I developed for the DNN Community, that utilizes the Tailwind CSS Framework. I soon discovered not many in the DNN Community know what Tailwind is.

Part 1: Tailwhat?

Background Info

Back in late June, I had received a discount offer to purchase a web editor called Pinegrow. After playing around with the free trial, I decided to purchase it for non-DNN related projects. Two weeks later I received an email from the developers letting me know they were releasing a Tailwind add-on for Pinegrow. "What the heck is Tailwind?" I thought, as I have never heard of it. I would be willing to bet that most of the DNN community has never heard of Tailwind, or if they have, they know very little about it (hence the need for a two part blog.)  Well being a curious person, I fired up a search engine, and went for a ride.

Tailwind CSS

What I found out is that Tailwind's full name is Tailwind CSS. It's a highly customizable, low-level, utility-first CSS framework that allows you to build custom designs without any annoying opinionated styles you have to fight to override, all while having to write very little, to no custom CSS. Wow, that was a mouth full, but what does that really mean?

Traditionally when you style elements on your webpage, you write custom CSS. With Tailwind, you style your elements by using pre-existing utility-classes right in your HTML, with very little need to write any css. If you have created webpages for any length of time like I have, you may remember the days before CSS, when all styling was done inline. Over time we have had "separation of concerns" beaten into us, so we moved on to separating our content (HTML) from our styling (CSS), and this became the accepted norm. So, when I read that styling elements is done right in our HTML, I thought this feels wrong. Turns out if you read quite a few posts on Tailwind, this is the first reaction of many developers.  However, when you start playing with Tailwind, you soon discover the benefits of this approach.

There are two other issues many developers are uncomfortable with when getting acquainted with Tailwind. The first is the potential of messier and/or bloated HTML code. The second is that Tailwind is so non-opinionated, even basic elements such as <p>, and <h1> - <h6> have no styling at all. Text in these elements just shows up as plain text (at the base font size) and are not affected by a browser's default built-in styling either. These are not bad things as it turns out, and both provide a significant benefit when creating your design.

Tailwind has thousands of utility classes at your disposal to help build custom designs, but the classes are given names which are descriptive and make sense. This makes picking up Tailwind relatively easy if you know CSS. The basic tailwind class syntax is:

property-value-modifier

There are variations to the basic syntax, as some properties have a sub-property like {location} or {axis}, not all values have a modifier, and pseudo classes and responsive sizing is done with prefixes.  Let's take a look at some examples of properties, values, modifiers and prefixes.

Margins and Padding (properties): We control margins and padding with m and p properties respectively, and can also specify the {location} sub-properties of top, right, bottom, left, with t, r, b, and l.   The {axis} (horizontal or vertical) sub-properties are specified with x or y.

Spacing (values): Sizing in Tailwind is based on rems, and 1 = .25 rems. Seeing there are 16px to 1 rem, .25 rem = 4px (16 x .25 = 4.) Following this logic in Tailwind, a spacing of 1 = 4px, 2 = 8px, 3 = 12px, 4 = 16px, etc.

Color Shades (modifiers): Just like there are 9 font-weights in vanilla CSS, (100 – 900), Tailwind also provides 9 shades of their default colors, also represented as 100 - 900 (100 lightest to 900 darkest).

Responsive Breakpoints (prefixes): Tailwind also has responsive mobile-first prefixes such as sm, md, lg, xl, and has support for both Flexbox and CSS Grid built in.

Putting It Together

Now lets put this all together with a couple of basic HTML examples. Say we want to create a title heading on our page, we might write it like this:

<h1 class="text-center font-sans font-bold text-indigo-700 text-5xl">
Hello World!
</h1> 
  

This will give us a Hello World! heading that is

  • centered on the page
  • uses a sans-serif font
  • is bold
  • has a deep shade of indigo blue
  • and has a size of 3 rems.

You may be looking at all the classes you have to write for an <h1> and be thinking to yourself: "What's the big deal? That's only a few characters less than I would have to type with my current CSS framework. Why would I ever want to switch?"

Let's take another common example, say that we want to create a styled button, we might write it like this:

<button class="bg-blue-500 text-white font-bold rounded py-2 px-4 hover:bg-blue-700">
Button
</button>
  

Breaking this down we see that the button will have

  • a background color with a middle shade of blue
  • the text will be white
  • the font will be bold
  • the corners will be rounded
  • there is vertical padding of 8px and a horizontal padding of 16px
  • If we hover over the button, the background color of blue will become 2 shades darker.

Now imagine all the CSS you would have to write if you used your current framework! As I mentioned earlier, your HTML can appear messy and bloated (with all these classes), but that is not necessarily a bad thing. As you can see, we can tell exactly what our button is going to look like, just by viewing the HTML, no digging through a long CSS file to figure it out. Oh wait, there is no CSS file to dig through as we didn't have to write any. Did a light bulb turn? Are you smiling yet?

Maybe you want this button style to be the default button style for your site, you can easily transform it into a custom component in Tailwind. In addition to custom components, Tailwind also provides several other methods to help keep you from duplicating yourself in your code. There is even a great little extension for VS Code called Tailwind CSS IntelliSense which makes adding your classes to your HTML a breeze.

Some other benefits of Tailwind CSS are:

  • Development speed is fast as you are not having to write (or write very little) CSS.
  • No more having to come up with class names that make sense and follow BEM naming conventions.
  • As your website or webapp grows, your css does not. You are just reusing exiting utility classes.
  • Highly customizable – just modify tailwind.config.js to overwrite, extend, or eliminate Tailwind's included utilitiy-classes.
  • Built on the PostCSS ecosystem which has 100’s of plugins to further customize your development environment.
  • Like DNN, the Tailwind community is awesome.

This blog is not meant to be a tutorial on Tailwind CSS, as that would take pages and hours to accomplish, which most likely neither of us have right now. Instead, it is meant to be a brief introduction to pique your interest, and to lay the groundwork for Part Two: DNN_Tailwind.

I have provided some useful links below about Tailwind CSS. I have also including a basic tailwind playground repo on github that you can clone, so you can quickly be up and running in a local tailwind environment to play around with it, if you desire.


References

I paraphrased content from the Tailwind website https://tailwindcss.com for the second paragraph.

Resources
Total: 3 Comment(s)
Excellent Steve!
Tuesday, August 25, 2020 ·

Error: Object reference not set to an instance of an object.

In: at DotNetNuke.Modules.Blog.Templating.LazyLoadingUser.GetProperty(String strPropertyName, String strFormat, CultureInfo formatProvider, UserInfo AccessingUser, Scope AccessLevel, Boolean& PropertyNotFound) at DotNetNuke.Modules.Blog.Templating.BaseCustomTokenReplace.replacedTokenValue(String strObjectName, String strPropertyName, String strFormat) at DotNetNuke.Modules.Blog.Templating.BaseTokenReplace.ReplaceTokenMatch(Match m) at System.Text.RegularExpressions.RegexReplacement.Replace(MatchEvaluator evaluator, Regex regex, String input, Int32 count, Int32 startat) at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator, Int32 count, Int32 startat) at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator) at DotNetNuke.Modules.Blog.Templating.BaseTokenReplace.ReplaceTokens(String strSourceText) at DotNetNuke.Modules.Blog.Templating.GenericTokenReplace.ReplaceTokens(String strSourceText) at DotNetNuke.Modules.Blog.Templating.Template.ReplaceContents()

Error: Object reference not set to an instance of an object.

In: at DotNetNuke.Modules.Blog.Templating.LazyLoadingUser.GetProperty(String strPropertyName, String strFormat, CultureInfo formatProvider, UserInfo AccessingUser, Scope AccessLevel, Boolean& PropertyNotFound) at DotNetNuke.Modules.Blog.Templating.BaseCustomTokenReplace.replacedTokenValue(String strObjectName, String strPropertyName, String strFormat) at DotNetNuke.Modules.Blog.Templating.BaseTokenReplace.ReplaceTokenMatch(Match m) at System.Text.RegularExpressions.RegexReplacement.Replace(MatchEvaluator evaluator, Regex regex, String input, Int32 count, Int32 startat) at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator, Int32 count, Int32 startat) at System.Text.RegularExpressions.Regex.Replace(String input, MatchEvaluator evaluator) at DotNetNuke.Modules.Blog.Templating.BaseTokenReplace.ReplaceTokens(String strSourceText) at DotNetNuke.Modules.Blog.Templating.GenericTokenReplace.ReplaceTokens(String strSourceText) at DotNetNuke.Modules.Blog.Templating.Template.ReplaceContents()

Would you like to help us?

Awesome! Simply post in the forums using the link below and we'll get you started.

Get Involved