Themes

Skeleton leans into Tailwind's best practices when implementing themes. This includes support for color opacity and dark mode. Themes also enable Skeleton's design tokens system.


CSS Custom Properties

Skeleton themes are generated using a number of CSS Custom Properties, also known as as CSS variables.

CSS PropertyDescription
--theme-font-family-base Set the font family for your default base text.
--theme-font-family-heading Set the font family for your heading text.
--theme-font-color-base Set the default text color for light mode.
--theme-font-color-dark Set the default text color for dark mode.
--theme-rounded-base Set the border radius for small elements, such as buttons, inputs, etc.
--theme-rounded-container Set the border radius for large elements, such as cards, textfields, etc.
--theme-border-base Set the default border size for elements, including inputs.
--on-[color] Set an accessible overlapping text or fill color per each theme color.
--color-[color]-[shade] Defines each color and shade value for your theme.

Overwriting Properties

Similar to variables in other languages, CSS properties can be overwritten. By adding the following snippet in /src/app.postcss, you can overwrite the base and container border radius styles for your active theme.

css
/* NOTE: set your target theme name (ex: skeleton, wintry, modern, etc) */

:root [data-theme='skeleton'] {
	--theme-rounded-base: 20px;
	--theme-rounded-container: 4px;
}

Likewise, you can override base and heading font family settings as shown below.

css
/* NOTE: set your target theme name (ex: skeleton, wintry, modern, etc) */

:root [data-theme='skeleton'] {
    --theme-font-family-base: 'MyCustomFont', sans-serif;
    --theme-font-family-heading: 'MyCustomFont', sans-serif;
}

For deeper customization, consider cloning Skeleton's preset themes, modifying each as desired, then implementing as a custom theme. Follow the theme generator implementation guide for more information.


CSS-in-JS Format

New in v2

Skeleton now defines theme settings via the CSS-in-JS format. This allows themes to be easily registered within the Skeleton Tailwind plugin, rather than relying on additional stylesheet imports.


Tailwind Plugin Settings

New in v2

Themes are configured via Skeleton's Tailwind plugin in your tailwind.config.[ts|js|cjs], found in your project root.

Register Themes

Skeleton provides a number of preset themes out of the box. You'll need to register at least one theme to load them and make them available to use.

typescript
plugins: [
	skeleton({
		themes: {
			// Register each theme within this array:
			preset: [ "skeleton", "modern", "crimson" ] 
		}
	})
]

Open /src/app.html and define the active theme to display using the data-theme attribute. You can modify this attribute to dynamically switch between any registered theme.

html
<body data-theme="skeleton">

Enhancements

Preset themes may sometimes include additional optional features, such as: heading font weights, background mesh gradients, and more. To enable these settings, include enhancements as shown below.

typescript
plugins: [
	skeleton({
		themes: {
			preset: [
				// Enable 'enhancements' per each registered theme:
				{ name: "skeleton", enhancements: true }
			] 
		}
	})
]

Custom Themes

View the theme generator for more information about implementing custom themes. Note that it is possible to mix and match preset and custom themes.


Dark Mode

By default Tailwind opts for light mode. If you wish to default to dark mode, append the following class to the html element within /src/app.html. View Tailwind's documentation for more information.

html
<html class="dark">

Note that Skeleton also provides a Lightswitch utility if you wish to toggle between light and dark modes.


Backgrounds

The background color of your application is automatically set using one of Skeleton's design token styles. By default, this utilizes --color-surface-50 for light mode and --color-surface-900 for dark mode. Use your global stylesheet app.postcss to modify this.

css
/* Default setting: */
body { @apply bg-surface-50-900-token; }

/* --- */

/* Example: primary color via a design token: */
body { @apply bg-primary-50-900-token; }

/* Example: secondary color via Tailwind: */
body { @apply bg-secondary-50 dark:bg-secondary-900; }

/* Example: using vanilla CSS: */
body { background: red; }
.dark body { background: blue; }

Images and Gradients

You may optionally provide a background image, including the use of a CSS mesh gradient. Replace the static color values with theme color properties to create a fully adaptive gradient background.

css
html, body { @apply h-full; }
body {
	background-image:
		radial-gradient(at 0% 0%, rgba(var(--color-secondary-500) / 0.33) 0px, transparent 50%),
		radial-gradient(at 98% 1%, rgba(var(--color-error-500) / 0.33) 0px, transparent 50%);
	background-attachment: fixed;
	background-position: center;
	background-repeat: no-repeat;
	background-size: cover;
}

Custom Fonts

Fonts may be installed from a local or remote source. For GDPR compliance and optimal performance we recommend installing the fonts locally. For this guide we'll demonstrate this process using free fonts from Google Fonts.

1. Download a Font

Select a font on Google Fonts, then tap the "Download Family" button near the top-right of the page.

2. Add the Font Files

Unzip the downloaded file, then copy all font files to the /static/fonts directory in the root of your SvelteKit project. When available we recommend using variable fonts as they require only a single file. Otherwise copy all static font file assets to the /static/fonts directory.

terminal
/static/fonts/Inter-VariableFont_slnt,wght.ttf

3. Apply @font-face

At the top of your global stylesheet /src/app.postcss append the @font-face settings per each font. The font-family assigns the font's reference name, while src points to the font file(s) in your /static/fonts directory.

css
@font-face {
	/* Reference name */
	font-family: 'Inter';
	/* For multiple files use commas, ex: url(), url(), ... */
	src: url('/fonts/Inter-VariableFont_slnt,wght.ttf');
}

4. Set the Font Family.

Use CSS Property overrides or open your custom theme to set the font family for base and heading properties. Be sure to use the same reference name set above or your font will not work.

css
/* NOTE: set your target theme name (ex: skeleton, wintry, modern, etc) */

:root [data-theme='skeleton'] {
    --theme-font-family-base: 'Inter', sans-serif;
    --theme-font-family-heading: 'Inter', sans-serif;
    /* ... */
}

5. Handle Font Flickering.

To avoid your page flickering during hydration, consider using the font-display descriptor for the @font-face at-rule that determines how a font face is displayed based on whether and when it is downloaded and ready to use.

Replace your @font-face at-rule with the following:

css
@font-face {
	/* Reference name */
	font-family: 'Inter';
	/* For multiple files use commas, ex: url(), url(), ... */
	src: url('/fonts/Inter-VariableFont_slnt,wght.ttf');
	/* Gives the font face an extremely small block period and an infinite swap period. */
	font-display: swap;
}