Astro

This guide will help create a basic Skeleton project using Astro, including adding components using Astro's island architecture.


Global Stylesheet

Let's start by creating a global stylesheet in /src/styles/global.css. Then add the following styles.

css
html, body { @apply h-full overflow-hidden; }

Layout Setup

We'll create a new Astro Layout in /src/layouts/LayoutRoot.astro. Our layout needs a bit of structure, so let's make use of the Skeleton App Shell component.

html
---
import '@skeletonlabs/skeleton/themes/theme-skeleton.css';
import '@skeletonlabs/skeleton/styles/all.css';
import '../styles/global.css';

import { AppShell, AppBar } from '@skeletonlabs/skeleton';
---

<!-- NOTE: we have set the .dark class to enable Dark Mode -->
<html lang="en" class="dark">
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width" />
		<meta name="generator" content={Astro.generator} />

		<!-- NOTE: customize your app title -->
		<title>Skeleton</title>
	</head>
	<body>
		<AppShell>
			<!-- Header -->
			<svelte:fragment slot="header">(header)</svelte:fragment>
			<!-- Sidebar -->
			<svelte:fragment slot="sidebarLeft">(sidebar)</svelte:fragment>
			<!-- Page Content Slot -->
			<slot />
		</AppShell>
	</body>
</html>

Add the App Bar

Next, let's add a header element using Skeleton's App Bar component. Replace "Skeleton" with your application name and customize the GitHub link as desired.

html
<svelte:fragment slot="header">
	<!-- Insert the App Bar: -->
	<AppBar>
		<svelte:fragment slot="lead">
			<h1>Skeleton</h1>
		</svelte:fragment>
		<svelte:fragment slot="trail">
			<a class="btn btn-sm" href="https://github.com/" target="_blank" rel="noreferrer">GitHub</a>
		</svelte:fragment>
	</AppBar>
	<!-- --- -->
</svelte:fragment>

Add Sidebar Navigation

Let's customize our App Shell's sidebar slot to make it stand out a bit more. Add the following Tailwind utility classes to the slotSidebarLeft prop.

html
<AppShell slotSidebarLeft="bg-surface-500/5 w-56 p-4">

After that, let's implement a Tailwind Elements navigation list within the App Shell's left sidebar slot.

html
<svelte:fragment slot="sidebarLeft">
	<!-- Insert the list: -->
	<nav class="list-nav">
		<ul>
			<li><a href="/">Home</a></li>
			<li><a href="/about">About</a></li>
		</ul>
	</nav>
	<!-- --- -->
</svelte:fragment>

Page Setup

Now that our layout is setup, let's implement it in our homepage in /src/pages/index.astro. Replace the file contents with the following. Be aware that we'll make use of the Gradient Heading import in a following step below.

html
---
import LayoutRoot from '../layouts/LayoutRoot.astro';
import { GradientHeading } from '@skeletonlabs/skeleton';
---
<LayoutRoot>
	<h1>Hello Skeleton</h1>
</LayoutRoot>

Now let's add some basic content to our homepage. Open /src/pages/index.astro and replace the contents within the LayoutRoot tags with the following. This will provide multiple "Tailwind Elements" styled by the all.css stylesheets.

html
<LayoutRoot>
	<div class="container mx-auto p-8 space-y-8">
		<h1>Hello Skeleton</h1>
		<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
		<hr />
		<section class="card p-4">
			<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
		</section>
		<hr />
		<section class="flex space-x-2">
		<a class="btn btn-filled-primary" href="https://kit.svelte.dev/" target="_blank" rel="noreferrer">SvelteKit</a>
		<a class="btn btn-filled-accent" href="https://tailwindcss.com/" target="_blank" rel="noreferrer">Tailwind</a>
		<a class="btn btn-filled-tertiary" href="https://github.com/" target="_blank" rel="noreferrer">GitHub</a>
		</section>
	</div>
</LayoutRoot>

These elements are styled automatically due to our use of all.css and the included Tailwind Elements stylesheets.

Add a Component

Let's implement Skeleton's Gradient Heading component. Replace the H1 heading on the page with the following. Feel free to adjust the settings and text as you wish.

html
<GradientHeading tag="h1" direction="bg-gradient-to-br" from="from-primary-500" to="to-accent-500">
	Homepage
</GradientHeading>

Island Architecture

Astro allows for partial component hydration via the Astro Island Architecture. Let's learn how to utilize this for Skeleton features.

Static Islands

Simple Svelte Components and Tailwind Elements require no Javascript functionality. This means they can be imported and used directly within your Astro page components with no hydration required.

html
---
import { Breadcrumb, Crumb } from '@skeletonlabs/skeleton';
---
<Breadcrumb>
	<Crumb href='/'>Home</Crumb>
	<Crumb>About</Crumb>
</Breadcrumb>

<a class="btn btn-filled-primary" href="/">Home</a>

Note: Because of the way Astro handles Svelte Components with props, there will be cases where you'll need to use a Wrapper Component as it is described in the next section to make the Component work properly.

Dynamic Islands

For more complex Svelte features--such as event handlers, Svelte Actions, using Svelte writable stores, and similar--we'll need to create Svelte "wrapper" component. Let's create one now in /src/components/WrapperExample.svelte, and insert a button which uses a Svelte on:click event handler.

html
<script lang="ts">
	function triggerMessage(): void { console.log('Hello, Skeleton'); }
</script>

<button class="btn btn-filled-primary" on:click={() => { triggerMessage() }}>Trigger</button>

We can then import our new wrapper component within an Astro page component, such as our homepage in /src/pages/index.astro.

html
---
import LayoutRoot from '../layouts/LayoutRoot.astro';

// ...
import WrapperExample from '../components/WrapperExample.svelte';
---
<LayoutRoot>
	<!-- ... --->
	<WrapperExample client:visible></WrapperExample>
</LayoutRoot>

Component Hydration

Please note that dynamic components MUST be hydrated using Astro's Client Directives. In the example above, we opted for the client:visible directive, which loads and hydrates the component Javascript only when it becomes visible the user’s viewport. Had we not hydrated our component, the triggerMessage() method would not work as expected.