npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

svelte-tiler

v0.7.0

Published

A small, unstyled library for building tiling user interfaces.

Readme

svelte-tiler

A small, unstyled library for building tiling user interfaces.

npm i svelte-tiler

Features:

  • Serializable state
  • Type-safe model extension
  • No external dependencies

Usage

<script>
  import { fromConstant } from 'svelte-tiler/shared/registry';
  import { Tiler, type Tiles } from 'svelte-tiler';
  import * as Leaf from 'svelte-tiler/tiles/leaf.svelte';
  import * as Tabs from 'svelte-tiler/tiles/tabs.svelte';

  const createLeaf = Leaf.setup(fromConstant(leaf));

  let layout = $state(
    Tabs.create({
      tabs: [
        ['Foo', createLeaf('foo')],
        ['Bar', createLeaf('bar')],
        ['Baz', createLeaf('baz')],
      ],
    })
  );
</script>

<Tiler bind:layout definitions={{ leaf: Leaf, tabs: Tabs }} />

{#snippet leaf(tile: Tiles['leaf'])}
  {tile.name}
{/snippet}

<style>
  :global {
    [data-tabs] {
      display: flex;
      flex-direction: column;
    }
    [data-tabs-bar] {
      display: flex;
    }
    [data-tabs-list] {}
    [data-tabs-header] {
      &[aria-selected='true'] {}
      &[data-over='true'] {}
    }
    [data-tabs-content] {
      flex-grow: 1;
      &[data-over='true'] {}
    }
  }
</style>

Mental Model

This section explains the conceptual model behind the library and how its core pieces fit together.

Tile

A Tile is the fundamental unit of the system. Everything in the layout is represented as a tree of tiles.

Base type definition:

export interface TileBase<T extends TileType> {
  id: string;
  type: T;
  children: Tile[];
}

export interface TileRegistry {}

export type TileType = keyof TileRegistry;

export type Tiles = {
  [T in TileType]: TileBase<T> & TileRegistry[T];
};

export type Tile = Tiles[TileType];

This definition:

  • Establishes a minimal structural contract (id, type, children)
  • Enables type-safe model extension via TileRegistry interface augmentation
  • Produces a discriminated union (Tile) based on registered tile types

By augmenting TileRegistry, you extend the model in a fully type-safe way without modifying the core types.

TileDefinition

In addition to its type definition, every tile must provide a behavioral definition.

Each tile exposes lifecycle hooks that are invoked by the tiler in order to perform structural mutations:

  • onInsert - invoked to perform insertion of a child tile at the specified index.
  • onRemoveChild - invoked to remove a child tile at the specified index.
  • onClear - invoked when the tile itself cannot be removed (e.g. the root tile) and must reset or clear its internal state instead.

Together with the Svelte component (export default), these hooks form a TileDefinition:

export type TileProps<T extends TileType> = {
  tile: Tiles[T];
  parent: Tile | undefined;
  index: number;
  child: Snippet<[number]>;
};

export type TileComponent<T extends TileType> = Component<
  TileProps<T>,
  {},
  'tile'
>;

export interface TileDefinition<T extends TileType> {
  default: TileComponent<T>;
  onInsert: (
    ctx: TilerContext,
    tile: Tiles[T],
    index: number,
    data: TileInsertData<T>
  ) => void;
  onRemoveChild: (ctx: TilerContext, tile: Tiles[T], index: number) => void;
  onClear: (ctx: TilerContext, tile: Tiles[T]) => void;
}

The tiler requests a structural change, but the tile fully controls how the mutation is performed.

For example, a Tabs tile may decide that when its last child is removed, it should remove itself instead by calling ctx.remove(tile). This mirrors the behavior of tab panels in editors such as VS Code.

This design keeps structural semantics inside the tile while the context provides the mutation primitives.

Layout

A Layout is a state tree that describes the UI structure.

Tiles form a hierarchical tree representing the entire arrangement. Mutations to this tree update the rendered structure reactively.

Standard tiles are designed so that layouts remain fully serializable. To support the serializable pattern, tiles typically export:

  • setup - installs runtime data into context and returns a parameterized create function.
  • create - produces tile data used in the layout.

Example:

export function setup<R extends string>(ctx: SplitContext<R>) {
  setContext(SPLIT_CONTEXT_KEY, ctx);
  return create<R>;
}

Context

The Tiler component internally works with a TilerContext, but you can also create and manage it manually.

[!NOTE] You can use a single TilerContext instance for multiple Panel components.

Example:

<script lang="ts">
  import { Panel, TilerContext, setTilerContext } from 'svelte-tiler';

  const ctx = new TilerContext({
    definitions: {
      /* your tiles */
    },
  });

  setTilerContext(ctx);
</script>

<Panel bind:layout />

Using a custom TilerContext allows you to:

  • Programmatically manipulate the layout
  • Interact directly with tile operations
  • Extend or wrap the context class to inject custom logic
  • Centralize control over layout behavior

This makes the system flexible while keeping the layout model predictable and strongly typed.

Customization

Standard tiles are intentionally shipped unstyled. All visual design decisions - must be implemented by the consumer after reviewing:

  • DOM hierarchy
  • Available data-* attributes
  • CSS custom properties

This approach keeps the core layout engine independent of styling concerns and ensures predictable integration into any design system.

If the standard tiles do not meet your requirements, you can freely copy the tile’s source code into your own project, apply the necessary modifications, and replace the import with your customized version.

License

MIT