Hello everyone! Today I am going to kickstart tutorial for Astro JS. This tutorial is taking into account you already know how to use Astro JS, we are starting from the button itself
An Astro button component is a reusable and customizable button used in Astro.js projects. It makes it easy to create buttons with different styles, sizes, and functions. Developers can define various button types (like primary, secondary, or outlined) and even include icons. This component helps keep the code clean and consistent, allowing for easier updates and a more unified look across the application.
The first thing we need to do is create a new file under the /components/fundations/buttons
folder. for example, and we are going to call it Button.astro
The following code represents the props destructuring and initialization section of an Astro button component. This part of the code pulls out the properties from the Astro.props object, making it easier to access and use them in your component.
Astro.props
into individual variables (variant
, size
, onlyIconSize
, gap
, className
). This makes the values easier to use in your component.const {
variant,
size,
onlyIconSize,
gap,
class: className,
...rest
} = Astro.props;
defaultClass
array defines a set of default Tailwind CSS classes for styling the button. This is the baseline style applied unless overridden by other variants.// Default button
const defaultClass = [
"text-white",
"bg-neutral-900",
"hover:bg-neutral-800",
"focus:ring-neutral-500/50",
];
// More variants go here
xs
, gapXS
, etc.) define classes for different button sizes and gaps. This allows the component to adjust its styling based on the specified size and spacing.// More variants go here
// Size
const xs = ["h-8", "px-4", "py-2", "text-xs", "font-medium", "rounded-md"];
// More sizes go here
// Gap
const gapXS = ["gap-2"];
additionalClasses
variable collects any extra classes passed through the class
prop, allowing for further customization of the button’s appearance.const additionalClasses = className ? className.split(" ") : [];
This section effectively sets up the component’s styling rules based on the props passed to it.
---
const {
variant,
size,
onlyIconSize,
gap,
class: className,
...rest
} = Astro.props;
// Default button
const defaultClass = [
"text-white",
"bg-neutral-900",
"hover:bg-neutral-800",
"focus:ring-neutral-500/50",
];
// More variants go here
// Size
const xs = ["h-8", "px-4", "py-2", "text-xs", "font-medium", "rounded-md"];
// More sizes go here
// Gap
const gapXS = ["gap-2"];
// More gaps go here
const additionalClasses = className ? className.split(" ") : [];
---
class:list
The <button>
element utilizes class:list
to conditionally apply Tailwind CSS classes based on the props passed to the component. This allows for dynamic styling based on different states or props.
Base Flex Classes:
"flex"
: Sets the button to use Flexbox layout."items-center"
: Vertically centers the items within the button."justify-center"
: Horizontally centers the items within the button."transition-all"
: Applies transition effects to all properties."duration-300"
: Sets the transition duration to 300ms."focus:ring-2"
: Adds a ring effect on focus."focus:outline-none"
: Removes the default outline when focused.Variant Classes:
accent
, default
, alternative
, etc.) has associated classes that are applied conditionally. For example:
variant === "accent" && accentClass
: If the variant
is "accent"
, accentClass
is applied.Size Classes:
size
prop. For instance:
size === "xs" && xs
: Applies the xs
size classes if the size is "xs"
.Gap Classes:
gap
prop.Additional Classes:
...additionalClasses
allows for any extra classes passed through the class
prop to be included, enabling further customization.<slot>
elements within the button component allow for flexible content placement:
<slot />
: The default slot for the button label or main content.{...rest}
: This syntax spreads any additional properties passed to the button component, allowing for further customization and functionality (e.g., event handlers, data attributes).This structure makes the button component highly customizable and adaptable to different use cases, ensuring it can serve various design needs.
<button
class:list={[
"flex",
"items-center",
"justify-center",
"transition-all",
"duration-300",
"focus:ring-2",
"focus:outline-none",
variant === "accent" && accentClass,
variant === "default" && defaultClass,
variant === "alternative" && alternativeaccentClass,
variant === "muted" && mutedClass,
variant === "info" && infoClass,
variant === "success" && successClass,
variant === "warning" && warningClass,
variant === "danger" && dangerClass,
variant === "text" && textClass,
variant === "link" && linkClass,
size === "xs" && xs,
size === "sm" && sm,
size === "base" && base,
size === "md" && md,
size === "lg" && lg,
size === "xl" && xl,
gap === "xs" && gapXS,
gap === "sm" && gapSM,
gap === "base" && gapBase,
gap === "md" && gapMD,
gap === "lg" && gapLG,
...additionalClasses,
]}
{...rest}>
<slot />
</button>
The whole button component
---
const {
variant,
size,
onlyIconSize,
gap,
class: className,
...rest
} = Astro.props;
// Default button
const defaultClass = [
"text-white",
"bg-neutral-900",
"hover:bg-neutral-800",
"focus:ring-neutral-500/50",
];
// More variants go here
// Size
const xs = ["h-8", "px-4", "py-2", "text-xs", "font-medium", "rounded-md"];
// More sizes go here
// Gap
const gapXS = ["gap-2"];
// More gaps go here
const additionalClasses = className ? className.split(" ") : [];
---
<button
class:list={[
"flex",
"items-center",
"justify-center",
"transition-all",
"duration-300",
"focus:ring-2",
"focus:outline-none",
variant === "accent" && accentClass,
variant === "default" && defaultClass,
variant === "alternative" && alternativeaccentClass,
variant === "muted" && mutedClass,
variant === "info" && infoClass,
variant === "success" && successClass,
variant === "warning" && warningClass,
variant === "danger" && dangerClass,
variant === "text" && textClass,
variant === "link" && linkClass,
size === "xs" && xs,
size === "sm" && sm,
size === "base" && base,
size === "md" && md,
size === "lg" && lg,
size === "xl" && xl,
gap === "xs" && gapXS,
gap === "sm" && gapSM,
gap === "base" && gapBase,
gap === "md" && gapMD,
gap === "lg" && gapLG,
...additionalClasses,
]}
{...rest}>
<slot />
</button>
This indicates that the code is using a reusable button component defined in your Astro project. This component accepts several props to control its behavior and appearance.
<Button
variant="default"
size="xs">
Button Default
</Button>
The props are used to customize the button’s appearance and behavior. Here are some examples that we are using in the component:
variant="default"
: This prop specifies the button’s style variant. In this case, “default” refers to a standard or primary button style with a predefined set of classes that determine its appearance (e.g., background color, text color, border style).size="xs"
: This prop indicates the button’s size. “xs” stands for “extra small,” which probably applies specific classes to reduce padding, height, and possibly font size compared to larger button sizes.Now that we have defined our button component, used it on our site, let’s add icons to it.
We ar estsrting by creating a new file under the /components/fundations/icson.astro
folder in this case and we are going to call it PlaceHolderIcon
, so the file name will be PlaceHolderIcon.astro
Ass you can see the the icon also has some props, like we did on our button, and here we adding a variants and sizes. You can also rehuse this props by just swapping the path with the one you want.
---
const { variant, size, class: className, ...rest } = Astro.props;
const xs = ["size-3"];
const sm = ["size-4"];
const base = ["size-5"];
const md = ["size-6"];
const lg = ["size-7"];
const xl = ["size-8"];
---
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class:list={[
"icon",
"icon-tabler",
"icons-tabler-outline",
"icon-tabler-layout-grid",
size === "xs" && xs,
size === "sm" && sm,
size === "base" && base,
size === "md" && md,
size === "lg" && lg,
size === "xl" && xl,
className,
]}
{...rest}>
<path
stroke="none"
d="M0 0h24v24H0z"
fill="none"
></path>
<path
d="M4 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"
></path>
<path
d="M14 4m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"
></path>
<path
d="M4 14m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"
></path>
<path
d="M14 14m0 1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1z"
></path>
</svg>
Now we have our icon but we need to tell the button that has to accpet icons also, so we are going to add a slot to the button component, and we are going to call it left-icon
and right-icon
for example.
<slot name="left-icon" />
: A designated area for an icon to the left of the button text.<slot name="right-icon" />
: A designated area for an icon to the right of the button text.<slot name="left-icon" />
<slot />
<slot name="right-icon" />
And this is how we are going to use it on our button component.
<Button variant="default" gap="xs" size="xl">
<PlaceHolderIcon size="lg" slot="left-icon" />
Button right icon
</Button>
<Button variant="default" gap="xs" size="xl">
Button right icon
<PlaceHolderIcon size="lg" slot="right-icon" />
</Button>
This is it, this is a simple button component that demonstrates how to use Tailwind CSS to create a button with a predefined set of styles, variants, sizes, and icons.
Hope you enjoyed this tutorial and have a great day!
/Michael Andreuzza
Get lifetime access to every theme available today for $199 $139 and own them forever. Plus, new themes, lifetime updates, use on
unlimited projects and enjoy lifetime support.
No subscription required!