Styling

Style the Lithesome components.

Lithesome components come completely unstyled out of the box, leaving that problem to you.

There are a few ways to style each component.

CSS Frameworks/libraries

If you’re using a CSS framework/library, simply pass their classes via the class prop of each component.

<MenuItem class="bg-red-400 text-lime-500">Edit</MenuItem>
<MenuItem class="bg-red-400 text-lime-500">Hide</MenuItem>
<MenuItem class="bg-red-400 text-lime-500">Delete</MenuItem>

Data attributes

Each component has their own unqiue html [data] applied to the underlying element. Simply target that attribute in your global css.

<MenuItem>Edit</MenuItem>
<MenuItem>Hide</MenuItem>
<MenuItem>Delete</MenuItem>
[data-menuitem] {
	background: red;
	color: lime;
}

To figure out what the data attribute is called, look at the component, add data infront and make them all lowercase.

<MenuContent> = [data-menucontent]
<SelectOption> = [data-selectoption]
ect…


CSS Selectors

if data attributes aren’t your cup of tea, you can always create your own classes and then apply them to the components.

<MenuItem class="menu-item">Edit</MenuItem>
<MenuItem class="menu-item">Hide</MenuItem>
<MenuItem class="menu-item">Delete</MenuItem>
.menu-item {
	background: red;
	color: lime;
}

Styling component states.

Most components have some sort of “state” to tell the browser what is checked, selected, opened, ect…
You have a couple of ways of style them accordingly.

[data-attributes]

Whenever there’s a “state” that is controlled by the components, they are exposed using [data] attributes.

For example:

  • [data-hovered] is exposed on the <MenuItem /> when the user has hovered over it, via mouse or keyboard.
  • [data-state="opened"] is exposed on the <Menu /> when the content of that menu is visible.

Check each component API reference to see what data attributes are exposed on each slot.


class prop function.

Each class prop exposed by the Lithesome components can be used as a function, giving you each state as a destructured parameter (if needed and exposed).

<SelectOption
	value="bobross"
	class={({ hovered, selected }) =>
		clsx(
			hovered && !selected ? 'bg-lime-400' : '',
			selected ? 'bg-teal-500' : '',
			'rounded-md px-4 py-2 text-xs font-medium'
		)}
>
	Bob Ross
</SelectOption>

This example uses clsx which is not required, but makes using the class function much easier to use.

NOTE: You cannot use these destructured props outside the class prop. They do not leave their scope.


Child props

With Svelte 5 slots have been replaced by Snippets.
This means you can no longer do let:prop on the component itself, but rather use a {#snippet children()} block to expose those props.

<SelectOption value="bobross">
	{#snippet children({ hovered, selected })}
		<span class={hovered ? 'ml-2' : ''}>Bob Ross</span>
		{#if selected}
			<CheckMarkIcon />
		{/if}
	{/snippet}
</SelectOption>

It’s not the nicest looking, but it apparently solves a lot of issues internally for svelte itself.

Since you’ll be composing your own components from these, you’ll likely come across a a snippet like this:

<script>
	import { SelectOption } from 'lithesome';

	let { children, value } = $props();
</script>

<SelectOption>
	{#snippet children({ selected })}
		{@render children()}
	{/snippet}
</SelectOption>

In this example, svelte looks at the #snippet children() and renders that in the @render block, causing an infinite loop.
To get around this, rename your local children prop to something else:

<script>
	import { SelectOption } from 'lithesome';

	let { children: inner, value } = $props();
</script>

<SelectOption>
	{#snippet children({ selected })}
		{@render inner()}
	{/snippet}
</SelectOption>