Playing Next Lesson In
seconds

EdgeJS Components #3.3

Adding Button Variants

In This Lesson

We'll add variant options for our base button. These will provide light and dark options as well as stateful coloring blue, green, red, and yellow.

Created by
@tomgobich
Published

Next, let’s add the six different color options for our base button, these will serve as our button variants.

  1. Light

  2. Dark

  3. Blue

  4. Red

  5. Green

  6. Yellow

Getting the Variant Classes

So, first, let’s go ahead and dive back into the Pines UI documentation and copy the variant markup, I’ll also provide it below for convenience.

<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-200 bg-white border rounded-md text-neutral-500 hover:text-neutral-700 border-neutral-200/70 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-200/60 focus:shadow-outline">
    Button
</button>

<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none">
    Button
</button>

<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-blue-600 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 focus:shadow-outline focus:outline-none">
    Button
</button>

<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-red-600 rounded-md hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-700 focus:shadow-outline focus:outline-none">
    Button
</button>

<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-green-600 rounded-md hover:bg-green-700 focus:ring-2 focus:ring-offset-2 focus:ring-green-700 focus:shadow-outline focus:outline-none">
    Button
</button>

<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-yellow-500 rounded-md hover:bg-yellow-600 focus:ring-2 focus:ring-offset-2 focus:ring-yellow-600 focus:shadow-outline focus:outline-none">
    Button
</button>
Copied!

To simplify our button markup, all we want from these size buttons is the class lists.

Cut Everything Except The Start Button Tag

First, since all we care about is the classes, we can cut everything except the start button tag.

<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-200 bg-white border rounded-md text-neutral-500 hover:text-neutral-700 border-neutral-200/70 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-200/60 focus:shadow-outline">
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none">
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-blue-600 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 focus:shadow-outline focus:outline-none">
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-red-600 rounded-md hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-700 focus:shadow-outline focus:outline-none">
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-green-600 rounded-md hover:bg-green-700 focus:ring-2 focus:ring-offset-2 focus:ring-green-700 focus:shadow-outline focus:outline-none">
<button type="button" class="inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-yellow-500 rounded-md hover:bg-yellow-600 focus:ring-2 focus:ring-offset-2 focus:ring-yellow-600 focus:shadow-outline focus:outline-none">
Copied!

Keep Just The Class Strings

Second, let’s get these button tags down to just class strings. We can use some keyboard shortcuts to drastically simplify this.

  1. Use multi-cursor to get one cursor per-line (Command + Control + Up/Down Arrow)

  2. Select from the start of the line to the start of our class value. You can select whole words using Option + Shift + Right Arrow.

  3. Delete the selection

  4. Jump to the end of the lines using Command + Right Arrow

  5. Replace the last two characters with a comma

  6. Remove these size classes (px-4 py-2 text-sm) from each line. You can jump over whole words using Option + Right/Left Arrow.

  7. Jump to the start and add key: . You can jump to the start of the line using Command + Left Arrow

  8. Then, replace the “key” with the appropriate variant name

    1. light

    2. dark

    3. blue

    4. red

    5. green

    6. yellow

At the end of this, you should be left with the below.

light: 'inline-flex items-center justify-center font-medium tracking-wide transition-colors duration-200 bg-white border rounded-md text-neutral-500 hover:text-neutral-700 border-neutral-200/70 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-200/60 focus:shadow-outline',
dark: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none',
blue: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-blue-600 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 focus:shadow-outline focus:outline-none',
red: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-red-600 rounded-md hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-700 focus:shadow-outline focus:outline-none',
green: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-green-600 rounded-md hover:bg-green-700 focus:ring-2 focus:ring-offset-2 focus:ring-green-700 focus:shadow-outline focus:outline-none',
yellow: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-yellow-500 rounded-md hover:bg-yellow-600 focus:ring-2 focus:ring-offset-2 focus:ring-yellow-600 focus:shadow-outline focus:outline-none',
Copied!

Set As Variants Object

Next, we’ll take what we have above and add it to an object for a variant called variants.

@set('size', size || 'base')
@set('sizes', {
  xs: 'px-2.5 py-1 text-xs',
  sm: 'px-3 py-1.5 text-sm',
  base: 'px-4 py-2 text-sm',
  lg: 'px-5 py-2.5 text-base'
})

@set('varaints', {
	light: 'inline-flex items-center justify-center font-medium tracking-wide transition-colors duration-200 bg-white border rounded-md text-neutral-500 hover:text-neutral-700 border-neutral-200/70 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-200/60 focus:shadow-outline',
	dark: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none',
	blue: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-blue-600 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 focus:shadow-outline focus:outline-none',
	red: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-red-600 rounded-md hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-700 focus:shadow-outline focus:outline-none',
	green: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-green-600 rounded-md hover:bg-green-700 focus:ring-2 focus:ring-offset-2 focus:ring-green-700 focus:shadow-outline focus:outline-none',
	yellow: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-yellow-500 rounded-md hover:bg-yellow-600 focus:ring-2 focus:ring-offset-2 focus:ring-yellow-600 focus:shadow-outline focus:outline-none',
})

<button 
  {{ $props.serializeExcept(['type', 'class']) }}
  x-data
  type="{{ type || 'button' }}"
  class="{{ sizes[size] }} {{ $props.class }} inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none">
  {{{ await $slots.main() }}}
</button>
Copied!
  • resources
  • views
  • components
  • button
  • index.edge

Let’s also take a second to plan for the next lesson, where we’ll add our styles. These styles will have variants of their own, so we can allow them to easily overwrite the variants we’ve defined above by setting our above variants as a default value for the prop variants.

@set('size', size || 'base')
@set('sizes', {
  xs: 'px-2.5 py-1 text-xs',
  sm: 'px-3 py-1.5 text-sm',
  base: 'px-4 py-2 text-sm',
  lg: 'px-5 py-2.5 text-base'
})

@set('varaints', variants || {
@set('varaints', {
	light: 'inline-flex items-center justify-center font-medium tracking-wide transition-colors duration-200 bg-white border rounded-md text-neutral-500 hover:text-neutral-700 border-neutral-200/70 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-200/60 focus:shadow-outline',
	dark: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none',
	blue: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-blue-600 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 focus:shadow-outline focus:outline-none',
	red: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-red-600 rounded-md hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-700 focus:shadow-outline focus:outline-none',
	green: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-green-600 rounded-md hover:bg-green-700 focus:ring-2 focus:ring-offset-2 focus:ring-green-700 focus:shadow-outline focus:outline-none',
	yellow: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-yellow-500 rounded-md hover:bg-yellow-600 focus:ring-2 focus:ring-offset-2 focus:ring-yellow-600 focus:shadow-outline focus:outline-none',
})

<button 
  {{ $props.serializeExcept(['type', 'class']) }}
  x-data
  type="{{ type || 'button' }}"
  class="{{ sizes[size] }} {{ $props.class }} inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none">
  {{{ await $slots.main() }}}
</button>
Copied!
  • resources
  • views
  • components
  • button
  • index.edge

Applying A Variant

Lastly, similarly to our sizes, we just need to apply a variant to our button. To simplify things we’ve kept all the button’s classes within our variant value. So, we can replace all the classes remaining on our button element with our variant.

We’ll also accept a prop called variant with a default value set to dark.

@set('size', size || 'base')
@set('sizes', {
  xs: 'px-2.5 py-1 text-xs',
  sm: 'px-3 py-1.5 text-sm',
  base: 'px-4 py-2 text-sm',
  lg: 'px-5 py-2.5 text-base'
})

@set('variant', variant || 'dark')
@set('varaints', variants || {
	light: 'inline-flex items-center justify-center font-medium tracking-wide transition-colors duration-200 bg-white border rounded-md text-neutral-500 hover:text-neutral-700 border-neutral-200/70 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-200/60 focus:shadow-outline',
	dark: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none',
	blue: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-blue-600 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 focus:shadow-outline focus:outline-none',
	red: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-red-600 rounded-md hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-700 focus:shadow-outline focus:outline-none',
	green: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-green-600 rounded-md hover:bg-green-700 focus:ring-2 focus:ring-offset-2 focus:ring-green-700 focus:shadow-outline focus:outline-none',
	yellow: 'inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 bg-yellow-500 rounded-md hover:bg-yellow-600 focus:ring-2 focus:ring-offset-2 focus:ring-yellow-600 focus:shadow-outline focus:outline-none',
})

<button 
  {{ $props.serializeExcept(['type', 'class']) }}
  x-data
  type="{{ type || 'button' }}"
  class="{{ variant[variant] }} {{ sizes[size] }} {{ $props.class }}">
  class="{{ sizes[size] }} {{ $props.class }} inline-flex items-center justify-center font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none">
  {{{ await $slots.main() }}}
</button>
Copied!
  • resources
  • views
  • components
  • button
  • index.edge

With this, we can now make use of our variants as follows.

@layout.app({ title: request.params().name })

  <h3 class="font-bold">Base Button</h3>
  <div x-data @click="alert('Thanks for clicking!')" class="mb-8 space-x-3 space-y-3">
    @button()
      Default, Base Button
    @end
  </div>

  {{-- ... --}}

  <h3 class="font-bold">Variants</h3>
  <div class="mb-8 space-x-3 space-y-3">
    @button({ variant: 'light' })
      Light Button
    @end

    @button({ variant: 'dark' })
      Dark Button
    @end

    @button({ variant: 'blue' })
      Blue Button
    @end

    @button({ variant: 'red' })
      Red Button
    @end

    @button({ variant: 'green' })
      Green Button
    @end

    @button({ variant: 'yellow' })
      Yellow Button
    @end
  </div>

@end
Copied!
  • resources
  • views
  • pages
  • components
  • buttons.edge

Join the Discussion 0 comments

Create a free account to join in on the discussion
robot comment bubble

Be the first to comment!