Playing Next Lesson In
seconds

EdgeJS Components #3.4

Adding Button Inverse and Outline Styles

In This Lesson

We'll add two new button style options, inverse and outline. Both styles will extend off the work we did with our base button to keep all functionality in one concise location

Created by
@tomgobich
Published

Lastly, for our button, we’ll be adding two additional styles, inverse and outline. Our approach for both of these styles is going to be relatively similar to how we did the variant options. However, we’ll be placing them inside separate files, extending from our base button.

Inverse Style

First, let’s make a new file for our inverse style.

touch resources/views/components/button/inverse.edge
Copied!

Inverse Variants

Then, just like we did with our variants in the last lesson, let’s copy the Pines UI markup for the inverse style and get it down to just the classes, again removing the size classes px-4 py-2 text-sm. Also, note that the inverse style only has five variants. There isn’t a dark variant, though you could always add one if you wish.

You should end up with the following.

'inline-flex items-center justify-center font-medium tracking-wide transition-colors duration-100 rounded-md text-neutral-500 bg-neutral-50 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-100 hover:text-neutral-600 hover:bg-neutral-100',
'inline-flex items-center justify-center font-medium tracking-wide text-blue-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-blue-100 bg-blue-50 hover:text-blue-600 hover:bg-blue-100',
'inline-flex items-center justify-center font-medium tracking-wide text-red-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-red-100 bg-red-50 hover:text-red-600 hover:bg-red-100',
'inline-flex items-center justify-center font-medium tracking-wide text-green-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-green-100 bg-green-50 hover:text-green-600 hover:bg-green-100',
'inline-flex items-center justify-center font-medium tracking-wide text-yellow-600 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-yellow-100 bg-yellow-50 hover:text-yellow-700 hover:bg-yellow-100',
Copied!

Then, let’s place the above into a variable called variants as an object.

@set('variants', {
  light: 'inline-flex items-center justify-center font-medium tracking-wide transition-colors duration-100 rounded-md text-neutral-500 bg-neutral-50 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-100 hover:text-neutral-600 hover:bg-neutral-100',
  blue: 'inline-flex items-center justify-center font-medium tracking-wide text-blue-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-blue-100 bg-blue-50 hover:text-blue-600 hover:bg-blue-100',
  red: 'inline-flex items-center justify-center font-medium tracking-wide text-red-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-red-100 bg-red-50 hover:text-red-600 hover:bg-red-100',
  green: 'inline-flex items-center justify-center font-medium tracking-wide text-green-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-green-100 bg-green-50 hover:text-green-600 hover:bg-green-100',
  yellow: 'inline-flex items-center justify-center font-medium tracking-wide text-yellow-600 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-yellow-100 bg-yellow-50 hover:text-yellow-700 hover:bg-yellow-100',
})
Copied!
  • resources
  • views
  • components
  • button
  • inverse.edge

Since our base button defaults to the dark variant and our inverse style doesn’t have a dark variants, we’ll also want to overwrite the variant prop, setting the default to light instead.

++@set('variant', variant || 'light')
@set('variants', {
  light: 'inline-flex items-center justify-center font-medium tracking-wide transition-colors duration-100 rounded-md text-neutral-500 bg-neutral-50 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-100 hover:text-neutral-600 hover:bg-neutral-100',
  blue: 'inline-flex items-center justify-center font-medium tracking-wide text-blue-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-blue-100 bg-blue-50 hover:text-blue-600 hover:bg-blue-100',
  red: 'inline-flex items-center justify-center font-medium tracking-wide text-red-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-red-100 bg-red-50 hover:text-red-600 hover:bg-red-100',
  green: 'inline-flex items-center justify-center font-medium tracking-wide text-green-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-green-100 bg-green-50 hover:text-green-600 hover:bg-green-100',
  yellow: 'inline-flex items-center justify-center font-medium tracking-wide text-yellow-600 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-yellow-100 bg-yellow-50 hover:text-yellow-700 hover:bg-yellow-100',
})
Copied!
  • resources
  • views
  • components
  • button
  • inverse.edge

Extending the Base Button

Next, thanks to the work we put into our base button, all we need to do now is extend our base button by passing everything for our inverse button into the base button.

@set('variant', variant || 'light')
@set('variants', {
  light: 'inline-flex items-center justify-center font-medium tracking-wide transition-colors duration-100 rounded-md text-neutral-500 bg-neutral-50 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-100 hover:text-neutral-600 hover:bg-neutral-100',
  blue: 'inline-flex items-center justify-center font-medium tracking-wide text-blue-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-blue-100 bg-blue-50 hover:text-blue-600 hover:bg-blue-100',
  red: 'inline-flex items-center justify-center font-medium tracking-wide text-red-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-red-100 bg-red-50 hover:text-red-600 hover:bg-red-100',
  green: 'inline-flex items-center justify-center font-medium tracking-wide text-green-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-green-100 bg-green-50 hover:text-green-600 hover:bg-green-100',
  yellow: 'inline-flex items-center justify-center font-medium tracking-wide text-yellow-600 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-yellow-100 bg-yellow-50 hover:text-yellow-700 hover:bg-yellow-100',
})

@button({
  ...$props,
  variant,
  variants
})
  {{{ await $slots.main() }}}
@end
Copied!
  • resources
  • views
  • components
  • button
  • inverse.edge

We’ll spread the $props directly into the button, overwriting the variant and variants properties for our inverse style.

As for our main slot, slots can’t be passed as props, so we’ll instead just go ahead and cascade the main slot by reapplying it into our base button.

Using our Inverse Button

Now, we should be good to go ahead and use our inverse button, via @button.inverse(). Everything we’ve added to our base button will now also be applied to our inverse button.

@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">Inverse</h3>
  <div class="mb-8 space-x-3 space-y-3">
    @button.inverse({ variant: 'light' })
      Light Button
    @end

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

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

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

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

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

Outline Style

Now let’s do the same process for our outline button, first creating a new outline.edge file for the component.

touch resources/views/components/button/outline.edge
Copied!

Outline Variants

Just like we did with our inverse style, let’s add a variants variable as an object with our different variant names as the keys and their respective classes as the values. Remember to remove the size classes px-4 py-2 text-sm from each.

@set('variants', {
  dark: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-100 bg-white border-2 rounded-md text-neutral-900 hover:text-white border-neutral-900 hover:bg-neutral-900',
  blue: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-blue-600 transition-colors duration-100 bg-white border-2 border-blue-600 rounded-md hover:text-white hover:bg-blue-600',
  red: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-red-600 transition-colors duration-100 bg-white border-2 border-red-600 rounded-md hover:text-white hover:bg-red-600',
  green: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-green-600 transition-colors duration-100 bg-white border-2 border-green-600 rounded-md hover:text-white hover:bg-green-600',
  yellow: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-yellow-600 transition-colors duration-100 bg-white border-2 border-yellow-500 rounded-md hover:text-white hover:bg-yellow-500',
})
Copied!
  • resources
  • views
  • components
  • button
  • outline.edge

Optionally, we can also reapply our default variant value. This isn’t needed, as the default for our outline (dark) matches the default for our base button (dark). For clarity sake, we’ll go ahead and do it anyways.

++@set('variant', variant || 'dark')
@set('variants', {
  dark: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-100 bg-white border-2 rounded-md text-neutral-900 hover:text-white border-neutral-900 hover:bg-neutral-900',
  blue: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-blue-600 transition-colors duration-100 bg-white border-2 border-blue-600 rounded-md hover:text-white hover:bg-blue-600',
  red: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-red-600 transition-colors duration-100 bg-white border-2 border-red-600 rounded-md hover:text-white hover:bg-red-600',
  green: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-green-600 transition-colors duration-100 bg-white border-2 border-green-600 rounded-md hover:text-white hover:bg-green-600',
  yellow: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-yellow-600 transition-colors duration-100 bg-white border-2 border-yellow-500 rounded-md hover:text-white hover:bg-yellow-500',
})
Copied!
  • resources
  • views
  • components
  • button
  • outline.edge

Extending the Base Button

Lastly, we just need to extend our base button, the exact same way we did with our inverse style.

@set('variant', variant || 'dark')
@set('variants', {
  dark: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-100 bg-white border-2 rounded-md text-neutral-900 hover:text-white border-neutral-900 hover:bg-neutral-900',
  blue: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-blue-600 transition-colors duration-100 bg-white border-2 border-blue-600 rounded-md hover:text-white hover:bg-blue-600',
  red: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-red-600 transition-colors duration-100 bg-white border-2 border-red-600 rounded-md hover:text-white hover:bg-red-600',
  green: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-green-600 transition-colors duration-100 bg-white border-2 border-green-600 rounded-md hover:text-white hover:bg-green-600',
  yellow: 'inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-yellow-600 transition-colors duration-100 bg-white border-2 border-yellow-500 rounded-md hover:text-white hover:bg-yellow-500',
})

@button({
  ...$props,
  variant,
  variants
})
  {{{ await $slots.main() }}}
@end
Copied!
  • resources
  • views
  • components
  • button
  • outline.edge

Using our Inverse Button

That should do it! We should be good to go ahead and use our outline button, via @button.outline(). Again, everything we’ve added to our base button will now also be applied to our outline button.

@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">Outline</h3>
  <div class="mb-8 space-x-3 space-y-3">
    @button.outline({ variant: 'dark' })
      Dark Button
    @end

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

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

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

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

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

Summary

That should wrap up our button component. We have our separate outline and inverse styles, which cascade through to our base button, which handles everything in one centralized location.

Plus, all three of our button styles have different variant options, as well as size options, and they handle interactivity both within the component and outside of the component just fine with AlpineJS and propagation.

Join the Discussion 0 comments

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

Be the first to comment!