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.edgeCopied!
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() }}} @endCopied!
- 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> @endCopied!
- 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.edgeCopied!
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() }}} @endCopied!
- 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> @endCopied!
- 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.