Overview
Svelte Atoms Core components are built with composability at their core. Components are organized into namespaces (like Dialog, Input, Dropdown) and use a compositional pattern where you combine multiple sub-components to build complex UIs.
Basic Component Usage
Simple Button
The simplest component to start with is the Button:
< script lang = "ts" >
import { Button } from '@svelte-atoms/core' ;
</ script >
< Button onclick = { () => console . log ( 'clicked' ) } > Click me </ Button >
< Button variant = "primary" > Primary Button </ Button >
< Button size = "sm" > Small Button </ Button >
Dialog Example
Dialogs follow a compositional pattern with multiple sub-components:
< script lang = "ts" >
import { Button , Dialog , Input } from '@svelte-atoms/core' ;
let dialogOpen = $ state ( false );
let inputValue = '' ;
</ script >
< Button onclick = { () => ( dialogOpen = true ) } > Open Dialog </ Button >
< Dialog . Root bind : open = { dialogOpen } >
< Dialog . Content >
< Dialog . Header >
< Dialog . Title > Enter your name </ Dialog . Title >
</ Dialog . Header >
< Dialog . Body >
< Input . Root >
< Input . Control bind : value = { inputValue } placeholder = "Your name..." />
</ Input . Root >
</ Dialog . Body >
< Dialog . Footer >
< Button onclick = { () => ( dialogOpen = false ) } > Cancel </ Button >
< Button variant = "primary" onclick = { () => ( dialogOpen = false ) } > Confirm </ Button >
</ Dialog . Footer >
</ Dialog . Content >
</ Dialog . Root >
Composable Components
Dropdown with Search
Combine Dropdown and Input components to create a searchable dropdown:
< script lang = "ts" >
import { Dropdown , Input , filterDropdownData } from '@svelte-atoms/core' ;
import { flip } from 'svelte/animate' ;
let data = [
{ id: 1 , value: 'apple' , text: 'Apple' },
{ id: 2 , value: 'banana' , text: 'Banana' },
{ id: 3 , value: 'cherry' , text: 'Cherry' }
];
let open = $ state ( false );
const dd = filterDropdownData (
() => data ,
( query , item ) => item . text . toLowerCase (). includes ( query . toLowerCase ())
);
</ script >
< Dropdown . Root
bind : open
multiple
keys = { data . map (( item ) => item . value ) }
onquerychange = { ( q ) => ( dd . query = q ) }
>
{# snippet children ({ dropdown })}
< Dropdown . Trigger
base = { Input . Root }
onclick = { ( ev ) => {
ev . preventDefault ();
dropdown . state . open ();
} }
>
{# each dropdown ?. state ?. selectedItems ?? [] as item ( item . id )}
< div animate : flip = { { duration: 200 } } >
< Dropdown . Value value = { item . value } > { item . text } </ Dropdown . Value >
</ div >
{/ each }
< Dropdown . Query placeholder = "Search..." />
</ Dropdown . Trigger >
< Dropdown . Content >
{# each dd . current as item ( item . id )}
< div animate : flip = { { duration: 200 } } >
< Dropdown . Item value = { item . value } > { item . text } </ Dropdown . Item >
</ div >
{/ each }
</ Dropdown . Content >
{/ snippet }
</ Dropdown . Root >
The filterDropdownData utility helps you filter dropdown items based on user input. It returns a reactive object with query and current properties.
Component Extensibility
Using base Props
Transform components by wrapping them with other components using the base prop:
< script lang = "ts" >
import { Button , Popover , Input } from '@svelte-atoms/core' ;
</ script >
<!-- Use Button as Popover trigger -->
< Popover . Root >
< Popover . Trigger base = { Button } variant = "outline" > Open Popover </ Popover . Trigger >
< Popover . Content class = "p-4" >
< h4 class = "font-semibold" > Settings </ h4 >
< p class = "text-sm" > Configure your preferences here. </ p >
</ Popover . Content >
</ Popover . Root >
<!-- Use Input.Root as Popover trigger -->
< Popover . Root >
< Popover . Trigger base = { Input . Root } >
< Input . Control placeholder = "Click to open popover..." readonly />
</ Popover . Trigger >
< Popover . Content class = "p-4" >
< p class = "text-sm" > Popover triggered by an input field </ p >
</ Popover . Content >
</ Popover . Root >
The base prop allows you to use any component as the base element, enabling powerful composition patterns.
Working with Animations
Svelte Animations
Seamlessly integrate with Svelte’s animation system:
< script lang = "ts" >
import { List , Button } from '@svelte-atoms/core' ;
import { flip } from 'svelte/animate' ;
import { slide } from 'svelte/transition' ;
let items = $ state ([
{ id: 1 , text: 'Task 1' },
{ id: 2 , text: 'Task 2' },
{ id: 3 , text: 'Task 3' }
]);
function removeItem ( id : number ) {
items = items . filter (( item ) => item . id !== id );
}
</ script >
< List . Root >
{# each items as item ( item . id )}
< div animate : flip = { { duration: 300 } } >
< List . Item >
< span > { item . text } </ span >
< Button size = "sm" onclick = { () => removeItem ( item . id ) } > Remove </ Button >
</ List . Item >
</ div >
{/ each }
</ List . Root >
Advanced Animations with Motion
Use lifecycle hooks for advanced animations:
< script lang = "ts" >
import { Dialog , Button } from '@svelte-atoms/core' ;
import { animate } from 'motion' ;
let open = $ state ( false );
</ script >
< Button onclick = { () => ( open = true ) } > Open Dialog </ Button >
< Dialog . Root bind : open >
< Dialog . Overlay
initial = { ( node ) => {
node . style . opacity = '0' ;
} }
enter = { ( node ) => {
const duration = 0.2 ;
const animation = animate ( node , { opacity: 1 }, { duration });
return { duration };
} }
exit = { ( node ) => {
const duration = 0.1 ;
const animation = animate ( node , { opacity: 0 }, { duration: 0.1 });
return { duration };
} }
/>
< Dialog . Content
initial = { ( node ) => {
node . style . opacity = '0' ;
node . style . scale = '0.95' ;
} }
enter = { ( node ) => {
const duration = 0.3 ;
const animation = animate (
node ,
{ opacity: 1 , scale: 1 },
{ duration , easing: 'ease-out' }
);
return { duration };
} }
exit = { ( node ) => {
const duration = 0.2 ;
const animation = animate (
node ,
{ opacity: 0 , scale: 0.95 },
{ duration , easing: 'ease-in' }
);
return { duration };
} }
>
< Dialog . Header >
< Dialog . Title > Animated Dialog </ Dialog . Title >
</ Dialog . Header >
< Dialog . Body >
< p > This dialog animates with custom Motion transitions using lifecycle hooks. </ p >
</ Dialog . Body >
< Dialog . Footer >
< Button onclick = { () => ( open = false ) } > Close </ Button >
</ Dialog . Footer >
</ Dialog . Content >
</ Dialog . Root >
Component Patterns
Root Component
Trigger Components
Content Components
Root components manage the overall state and context for a component group. < Dialog . Root bind : open = { dialogOpen } >
<!-- Child components -->
</ Dialog . Root >
Common Root Props:
open - Control visibility
disabled - Disable interactions
factory - Custom bond factory
Trigger components initiate interactions like opening dialogs or dropdowns. < Popover . Trigger base = { Button } variant = "outline" >
Open
</ Popover . Trigger >
Common Props:
base - Base component to wrap
Event handlers (onclick, onkeydown, etc.)
Content components display the main UI elements. < Dialog . Content >
< Dialog . Header >
< Dialog . Title > Title </ Dialog . Title >
</ Dialog . Header >
< Dialog . Body >
<!-- Content -->
</ Dialog . Body >
< Dialog . Footer >
<!-- Actions -->
</ Dialog . Footer >
</ Dialog . Content >
Next Steps
State Management Learn about bonds and Svelte 5 runes for state management
Customization Discover how to customize components with variants and props
TypeScript Explore TypeScript support and type definitions
API Reference Browse the complete API documentation