Modern & Responsive TailwindCSS form in 5 minutes

July 2, 2024 5 mins TailwindCSS

Creating a modern looking form using TailwindCSS is very straight forward. This guide will take you through the steps needed to get a simple form up and running. All the sample used in this post can also be found at: tailwind-modern-form

Prerequisites

  • TailwindCSS added to your project

Barebones form markup

The below markup will be used as the base for adding our TailwindCSS classes later.

<form>
  <div>
    <div>
      <label for="f_name">First name (required):</label>
      <input type="text" name="f_name" id="f_name" required>
    </div>
    <div>
      <label for="l_name">Last name  (required):</label>
      <input type="text" name="l_name" id="l_name" required>
    </div>
  </div>
  <div>
    <div>
      <label for="p_number">Phone number  (required):</label>
      <input type="text" name="p_number" id="p_number" required>
    </div>
    <div>
      <label for="contact_type">Contact Type (required):</label>
      <select name="contact_type" id="contact_type" required>
        <option value="default" disabled selected>Select contact type</option>
        <option value="0" >Mobile</option>
        <option value="1" >Home</option>
        <option value="2" >Work</option>
      </select>
    </div>
  </div>
  <div>
    <label for="email">Email  (required):</label>
    <input type="email" name="email" id="email" required>
  </div>
  <div>
    <label for="event_date">Event date (required):</label>
    <input type="date" name="event_date" id="event_date" required>
  </div>
  <div>
    <input type="submit" value="Book appointment">
  </div>
</form>

The form display should look similar to the one below, not much to look at, but we will clean it up very shortly.

Add TailwindCSS to our markup

Now that we have our markup in place, lets sprinkle a bit of Tailwind magic to get our form looking a bit better and responsive.

<form>
  <div class="grid grid-cols-1 md:grid-cols-2 md:gap-8 gap-4 mb-4">
    <div class="md:mb-4 flex flex-col col-span-2 md:col-span-1">
      <label class="pb-1" for="f_name">First name (required):</label>
      <input type="text" name="f_name" id="f_name" required>
    </div>
    <div class="md:mb-4 flex flex-col col-span-2 md:col-span-1">
      <label class="pb-1" for="l_name">Last name  (required):</label>
      <input type="text" name="l_name" id="l_name" required>
    </div>
  </div>
  <div class="grid grid-cols-1 md:grid-cols-3 md:gap-8 gap-4 mb-4">
    <div class="md:mb-4 flex flex-col col-span-3 md:col-span-2">
      <label class="pb-1" for="p_number">Phone number  (required):</label>
      <input type="text" name="p_number" id="p_number" required>
    </div>
    <div class="md:mb-4 flex flex-col col-span-3 md:col-span-1">
      <label class="pb-1" for="contact_type">Contact Type (required):</label>
      <select name="contact_type" id="contact_type" required>
        <option value="default" disabled selected>Select contact type</option>
        <option value="0" >Mobile</option>
        <option value="1" >Home</option>
        <option value="2" >Work</option>
      </select>
    </div>
  </div>
  <div class="md:mb-4 flex flex-col mb-4">
    <label class="pb-1" for="email">Email  (required):</label>
    <input type="email" name="email" id="email" required>
  </div>
  <div class="md:mb-4 flex flex-col mb-4">
    <label class="pb-1" for="event_date">Event date (required):</label>
    <input type="date" name="event_date" id="event_date" required>
  </div>
  <div class="md:mt-4">
    <input class="w-full bg-gray-100 hover:bg:gray-200 bh-schedule-appointment-submit" type="submit" value="Book appointment">
  </div>
</form>

We have one final bit to update, our style.css file. Instead of adding the same repetitive classes to the label, input and select elements we will be targeting them using the @layer directive.

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  input,
  select {
    @apply border rounded p-2;
  }
  label {
    @apply text-sm font-semibold uppercase pb-1;
  }
}

Now all input, select and label elements will be default inherit the classes “applied” via the @apply function.

With all the above style updates completed our form should now look like the below for the respective viewports:

Desktop:

Mobile:

Conclusion

Adding styles to a form using TailwindCSS is very straight forward and allows you to quickly prototype an idea. TailwindCSS has gotten a lot of flak for being verbose when used directly on markup. The @layer directive is a huge help with cleaning up your code and can be explored when looking to package your code in a class.

How to fix SVN using wrong SQLite version on MacOS

June 16, 2024 1 min Troubleshooting

If you ever happen to need to upgrade your SQLite version outside of a MacOS update it can be a little be unclear as to the next steps, at least it was for me. I was attempting to utilize Subversion (SVN) via the CLI to update a repository and every attempt to do so would fail with the below error:

svn: E200029: Couldn't perform atomic initialization
svn: E200030: SQLite compiled for 3.43.2, but running with 3.39.5

It was an extremely annoying error to navigate, especially after trying so many different approaches. I was able to resolve the issue by executing the following commands. Note: in my case I was using HomeBrew.

brew update
brew remove sqlite svn
brew reinstall sqlite svn --build-from-source

Once that is done if you execute sqlite3 --version you should now see that you have the latest version installed and be able to utilize SVN.

Good luck!

Modern Software Architecture 101: What is Design and Architecture?

March 22, 2024 6 mins Architecture

If you are new to software architecture, you may have seen a lot of material trying to decouple design from architecture or vice versa. The goal of this article is to show how each complements the other and why they are a sum of a whole. We will be reviewing a case study to break down how bad software architecture can affect developer productivity and the effects it can have on a company’s finances.

Software architecture vs design

What is architecture? What is design?  Is architecture and design mutually exclusive? From my perspective no, they are not mutually exclusive. Architecture and design are the sum of a whole. As we go further into the topic my goal is to clear up a lot of the confusion around the matter and provide practical examples to support my point of view.

To establish a baseline of understanding I took the below definitions from IEEE Computer Society.

“Software architecture – refers to the high-level structures of a software system and the discipline of creating such structures. It involves the set of significant decisions about the organization of a software system including the selection of structural elements and their interfaces by which the system is composed and behavior as specified in collaborations among those elements.” – https://www.computer.org/resources/software-architecture

“Software design – describes how the software system is decomposed and organized into components and modules. It defines the relationship between these modules through interfaces. Software design translates the user’s requirements into a ‘blueprint’ for building the software. It is the link between problem space and solution space. The design represents the software architects’ understanding of how to meet the requirements.” – https://www.computer.org/resources/importance-of-software-design-is-important

Just going based on the definitions above its very hard to draw a line to say one can exist without the other. Instead we should view software architecture as more of an all encompassing software principle.

Lets look at an example, albeit a very cliche one; but it drives home the point succinctly. You are in the process of building your dream home, you have an idea in mind head of what you need done but you need an architect to put your vision to paper so the contractors can execute. Now lets look at two possible scenarios that we can pull from this example:

Scenario 1: Complete architecture – high and low level considerations

Architect delivered to you a complete plan. It has the high level requirements such as the size of the structure and the placement of the rooms. On the other hand it has all the low level details too, where the doors, windows, electrical outlets and plumbing should be.

In this scenario you can feel comfortable knowing all the requirements were considered and the plan is in keeping with your vision.

Scenario 2: Incomplete architecture – high level considerations only

Architect delivered to you a plan. It has only the high level requirements such as the size of the structure and the placement of the rooms. The low details are left to the discretion  of the contractor, so doors, windows, electrical outlets can be placed anywhere the contractor sees fit.

I don’t know about you but for me personally I do not like the idea of having key areas of my dream home left to chance. Who knows I might just end up with all my electrical outlets placed in the worse possible areas because it was faster to install versus doing it right.

The concepts of design and architecture works hand in hand, any system that is being designed to not just work but scale and not require an army behind to keep it running needs to properly plan its architecture.

Case Study: Effects of Bad Software Architecture

In order to set the stage for articles to come, let us explore a case study. This study is based on a personal experience, as such company details will remain anonymous.

As engineers, we all love greenfield projects; however, we can get a bit ahead of ourselves in terms of how the project is approached and designed. Unfortunately, we were victims of this over-exuberance. Our company was first to market in the region with a product of this nature, and we were able to gain massive value from our first few releases. However, as time progressed, the time between major releases increased and the operating overhead increased to boot.

You may be wondering, how did you get there? Well, in hindsight, we allowed “urgency” to take precedence over important fundamental activities, which needed to ensure this product would bring value for releases to come. There are a few important and often overlooked areas of any software development project:

  • Quality architecture that is easy to implement and maintain. What do I mean by this? Well, a system where your complexity is directly related to the operational overhead needed to keep it running is a poorly designed one. The goal is to deliver the most value possible to stakeholders while having the flexibility to add new features over time.
  • Eliminating the “we will fix it next release” mindset. Let’s be real, there is technical debt in every system, but we tend to use the term as a blanket statement to kick the proverbial can down the road. Except there is one main issue with this, we hardly ever have the capacity to tackle these items, which eventually comes back to bite us.

Unfortunately, we got to a point where we needed to redesign this system from the ground up, as we were no longer in a position to deliver value in a timely manner to the business. As you can imagine, this did not go down well from an executive level. With the lessons learned from attempt one, we were able to put together a system which was much more robust than previously implemented. The bad test of cost and loss of business during this rebuild period was certainly not lost on senior leadership.

Conclusion

In order to deliver a quality product to your stakeholders, we can’t leave anything to chance. Consideration has to be given to both high and low-level details of the software architecture. Otherwise, we run the risk of making the same mistakes made by others and implementing a system that has a predetermined value lifecycle for the business.

How to register settings field with custom options page in WordPress

January 1, 2024 5 mins Plugin

This guide will show you how to register a field for your WordPress plugin, and have it shown on a custom options page.

1. Prerequisites

  • ⁠An instance of WordPress running with the plugin requiring new settings field.

2. Register setting field

The recommended approach to adding settings to a WordPress plugin is via the Settings API. The main benefits are: as a plugin developer you inherit the general theming from WordPress (if that is something you are looking for), your plugin gets future proofed for new releases of WordPress, and finally, there is less work to be done to accomplish standard behaviours. Check out the WordPress Settings API for more details.

We will be using register_setting, add_settings_section and add_settings_field methods in order to complete the process of registering and adding our settings fields.

For our demo, we developed SJ Reading Time plugin which estimates the reading time of an article based on the word count, as well as the total images included in the post. Below is a snippet of the code used to register our sjrt_settings_wpm and sjrt_settings_include_images setting options.

/**
* Register settings fields 
*/

function sjrt_settings_init() {
  register_setting('sjrt','sjrt_settings_wpm');
  register_setting('sjrt','sjrt_settings_include_images');

  add_settings_section(
    'sjrt_section_settings',
    'Reading Time Configuration',
    array($this,'sjrt_section_settings_shortcode_cb'),
    'sj-reading-time'
  );

  add_settings_section(
    'sjrt_section_settings_shortcode',
    'Shortcode',
    array( $this,'sjrt_section_settings_shortcode_cb' ),
    'sj-reading-time'
  );

  add_settings_field(
    'sjrt_settings_wpm',
    'Words Per Minute', 
    array( $this, 'sjrt_setting_field_wpm_cb' ),
    'sj-reading-time','sjrt_section_settings', 
    array('label_for' => 'sjrt_settings_wpm')
  );

  add_settings_field(
    'sjrt_settings_include_images', 
    'Include images?', 
    array( $this, 'sjrt_setting_field_include_images_cb'), 
    'sj-reading-time', 
    'sjrt_section_settings', 
    array('label_for' => 'sjrt_settings_include_images')
  );
  

}

Note: once you have defined your own custom options page, you will need to create a section inorder to utilize the settings_fields method to display your fields.

With your settings registered, the first interaction with the admin dashboard will trigger the registration process. It is recommended that the init method (sjrt_settings_init) is triggered with the admin_init hook.

3. What is a callback?

In the case of registering a settings field, the callback function is what is used to present the setting field to your user in the WordPress dashboard. Basically, if there is no callback function then there is no setting presentation to your user.

Below is a sample of our callback function for our settings fields.

/**
* Callback to display wpm field, method used with add_settings_field for
* id sjrt_settings_wpm.
*/
function sjrt_setting_field_wpm_cb( $args ) {
  $setting_wpm = get_option('sjrt_settings_wpm'); ?>

  <input type="number" name="sjrt_settings_wpm" 
    value=
      "<?php echo isset($setting_wpm) ? esc_attr( $setting_wpm ) : '';  ?>"
  >
    <p>By default the average wpm is set to 250.</p>
    <?php
  }

/**
* Callback to display wpm field, method used with add_settings_field for id
* sjrt_settings_include_images.
*/

function sjrt_setting_field_include_images_cb( ) {
  $setting_include_image = get_option('sjrt_settings_include_images'); ?>

  <input type="checkbox" name="sjrt_settings_include_images" 
    value="true" 
    <?php echo $setting_include_image == true ? 'checked' : '' ?> 
  >
    <p>By default an additional 10 seconds is added to your post read time
       for each image. Uncheck to remove additional time consideration.</p>
    <?php
  }

With the settings fields registered and callbacks implemented our setting fields will be displayed similar to the below:

Example WordPress settings page with custom fields added via Settings API

4. Conclusion

Registering your own settings via the Settings API is pretty simple, once you get the hang of it. From my experience thus far utilizing this approach has been great when the focus is blending in with the WordPress dashboard standards. If you are looking for a more custom experience you might see value in deviating from this approach.

How to create a custom list marker using Tailwind

March 2, 2023 3 mins TailwindCSS

This quick and easy guide will show you how to create your own custom list markers to suit your design. All the code used in this demo can be found in our repository: tailwind-custom-list-marker.

1. Prerequisites

  • TailwindCSS added to your project

2. Adding Tailwind to our markup

Below is a sample ordered list which we will be using for our demo project:

    <ol>
        <li>
            First item
        </li>
        <li>      
            Second item
        </li>
    </ol>

The list should display as shown below if there are no default styles being applied to your list:

Lets add a few Tailwind classes to our our markup:

    <ol class="ml-4">
        <li class=" my-6
            before:content-['1'] before:text-purple-400 before:text-2xl 
            before:ring-2 before:ring-offset-2 before:ring-purple-500
            before:px-3 before:py-1 before:rounded-full
            before:mr-4
        ">
            First item
        </li>
        <li class=" my-6
            before:content-['2'] before:text-purple-400 before:text-2xl 
            before:ring-2 before:ring-offset-2 before:ring-purple-500
            before:px-3 before:py-1 before:rounded-full
            before:mr-4
        ">      
            Second item
        </li>
    </ol>

With the above styles applied our list should look like the below:

3. Conclusion

Tailwind also supports the ::marker CSS psuedo-element. However, it comes with a few limitations; only a limited set of properties are supported. Any complex styling needed won’t be able to accomplished with these properties. For a full list of currently supported properties, check out the MDN Docs. The approach taken in this guide gives us the most flexibility from a styling point of view via the ::before psuedo-element.

How to quickly add Tailwind to an existing Jekyll site

February 23, 2023 4 mins TailwindCSS

The goal of this how to guide is to show you how to quickly include Tailwind CSS in your existing Jekyll site and build using the Tailwind CLI. All the code used in this demo can be found in our repository: jekyll-tailwindcss.

1. Prerequisites

  • Existing Jekyll site
  • Node.js installed

2. Install Tailwind CLI

Navigate to the root directory of your existing Jekyll site and running the below commands. These commands will install ‘tailwindcss’ as node module in your project as a dependency and initialise TailwindCSS.

npm install -D tailwindcss
npx tailwindcss init

After running the above commands you will notice a few differences with your directory, such as the inclusion of a node_modules directory and package.json files. The key file we will be focusing on however is the tailwind.config.js.

The contents of your tailwind.config.js file should be similar to the below:

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: [],
    theme: {
        extend: {},
    },
    plugins: [],
}

At this point we now have TailwindCSS installed and initialised, however there is a little bit of configuring we will need to do in order to start using it in our mark up. We need to make Tailwind aware of the paths it needs to keep track of for the various classes we will be adding to our markup. For the purpose of this guide we need to keep track of files in _includes, _layouts and markdown files in our root directory.

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: [ 
        '_includes/**/*.html',
        '_layouts/**/*.html',
        '*.markdown'
    ],
    theme: {
        extend: {},
    },
    plugins: [],
}

With the content array updated, Tailwind will be able to apply its styling to any .html file found in _includes, _layouts and similarly any .markdown file found on the root level of our project.

Lets now add the Tailwind directives to our main css file:

@tailwind base;
@tailwind components;
@tailwind utilities;

3. Adding Tailwind to our markup

The content I have in place for my basic site isn’t looking so great at the moment, there is no styling in place. Lets add a bit of styling to clean this up a bit.

In order to starting seeing the Tailwind classes take effect on your website you will need to run the below command.

npx tailwindcss -i ./assets/css/style.css -o ./assets/dist-style.css --watch

Note: if your CSS file is in another location you will need to update this command to reference it.

Lets start by adding a bit of styling to the header of demo site:

<header class="bg-slate-100">
    <div class="max-w-screen-lg mx-auto h-24 flex items-center">
        <a href="/">
            <h1 class="text-black text-3xl font-bold">Jekyll - TailwindCSS Demo</h1>
        </a>
    </div>
</header>

Once I refresh my browser I can immediately see the updates taking place.

We won’t cover Tailwind in detail in this post, if you are looking for more information on how to use Tailwind check out there official docs. After applying all the classes I need to clean up this page I end up with the below as my finished product:

If you would like to see all the code behind doing this you can clone the repository for this project: jekyll-tailwindcss.

All best on your journey with Tailwind & Jekyll!

5 preparation tips for AZ-900 Azure Fundamentals Exam

February 2, 2023 2 mins Microsoft Azure

Our approach to IT infrastructure and how we deliver software solutions has been changing over the years due to a wider adaptation of cloud computing. As a developer I needed to expand my understanding of cloud computing and how it affects my approach to design and delivery of solutions.

I am currently focused on learning Microsoft Azure, due to its usage within my organization . To date, I have earned two certifications; Microsoft Certified: Azure Fundamentals and Microsoft Certified: Azure Administrator Associate. I am currently preparing for another exam and realized that hearing someone’s experience has been really helpful in how I prepare. With that being said here are a few tips that could be useful when preparing for the AZ-900 Microsoft Azure Fundamentals:

  1. Study to understand the concepts – This exam is rather light; however, I found a lot of the questions asked will be scenario based. You will be tested on your ability to recall and apply the knowledge to a situation.
  2. Give yourself enough time to prepare – Don’t rush the preparation. Take your time to cover the material as this will act as the foundation for other associate level exams going forward.
  3. Sign up an Azure account – Microsoft offers a free trial that you can use to play around with their services. This will be really helpful in building familiarity with the services and the environment.
  4. Prepare according to the skills measured by Microsoft – There is a lot of content out there; ensure that you are first and foremost guided by the official Microsoft exam breakdown. If you are looking at learning resources for the exam separate from what is provided by Microsoft, ensure you can see the breakdown in the course material being provided by the third party.
  5. Complete a practice test – For me it was useful to have an idea of the sort of questions that are asked, as well as test myself before going into the exam. This allowed me to gauge how ready I was and could make the necessary adjustments. I found the MeasureUp practice tests to be really useful in that regard, especially with the feedback that explains why my answer was wrong. Note: This is not absolutely necessary.

All the best on your upcoming exam!