Skip to content

Features

A handful of additional features have been implemented in the Svelte layer of the project.

Additions

๐Ÿ”—

Draggability

๐Ÿ”—

With a single prop, you can make a <Pane> draggable and resizable. Position and size are persisted in local storage. (This is the default behavior for <Pane> components.)

What a time to be alive.

Pains were taken during development of this feature to ensure that draggable components behave appropriately on touch devices. Itโ€™s true that Tweakpaneโ€™s hit-zones are decidedly โ€œmouse-firstโ€, but the scale property on <Pane> can be used to make things more touch-friendly.

Inline components

๐Ÿ”—

You can make a <Pane> appear inline with the rest of your content. (This is the default for standalone components.)

Additional value types

๐Ÿ”—

In several places, additional value types are transparently supported.

Throughout the library, almost anything that takes an object will now also tolerate a tuple, and vice versa.

For example, <Point> can be used with a tuple, and <CubicBezier> can be used with an object.

This is particularly useful for interoperability with tuple-loving libraries like Three.js / Threlte.

Scaling

๐Ÿ”—

Tweakpane is nearly bitmap-free, so it scales up very nicely. Svelte Tweakpane UI adds a scale prop to <Pane>s to allow you to scale your panes to any size you like.

Scoped theming

๐Ÿ”—

Svelte Tweakpane UI manages applying and overriding CSS variables at the right points in the dom to allow multiple panes to be styled independently on a single page.

Global theming

๐Ÿ”—

A setGlobalDefaultTheme() helper function makes it easy to define a default theme for all panes on a page. (While still allowing individual panes to override the global default.)

Element component

๐Ÿ”—

Sometimes you want to embed an arbitrary chunk of HTML in one of your panes. The <Element> component simplifies this.

Live text updates

๐Ÿ”—

<Text> and <Textarea> components update their bound values every keystroke, not just on blur. (Though the old behavior remains is available via a prop.)

Implicit Panes

๐Ÿ”—

Wrapping Tweakpane components in <Pane> components is optional. If you donโ€™t wrap a component in a <Pane>, it will be automatically wrapped in an implicit inline <Pane> with default settings.

SSR Support (experimental)

๐Ÿ”—

Very, very, early and experimental support around SSR pre-rendering of pane width and height only. This is not true SSR, just some calculations to minimize CLS after hydration.

Automatic collapsibility

๐Ÿ”—

Folders and inline pickers inside a draggable <Pane> can be set to automatically collapse if the screen is short on vertical space via the collapseChildrenToFit prop.

Control user collapsibility

๐Ÿ”—

If you want to prevent the user from collapsing chunk of pane, you can set the userExpandable prop to false. The section will remain programmatically collapsible via the expanded property.

Label truncation

๐Ÿ”—

Pane titles and blade labels are truncated with ellipses if theyโ€™re too long to fit in their containers.

Value change event origins

๐Ÿ”—

Though binding to a componentโ€™s value is generally the best way to react to changes, sometimes you need to know how a valueโ€™s change originated.

To this end, all value-manipulating components provide a change event that includes the โ€œoriginโ€ of the change in the event.details payload.

Changes resulting from the userโ€™s direct manipulation of the control are marked as internal, while those resulting from a change to the bound value from outside the component are marked as external.

The example below tallies internal vs. external changes to the <Slider>:

See example code
SvelteTweakpaneEventExample.svelte
<script lang="ts">
import {
Button,
Monitor,
Slider,
type SliderChangeEvent
} from 'svelte-tweakpane-ui';
let speed = 50;
// Keep track of how many Slider change events originated from direct
// interaction with the slider (internal) vs. programmatic changes set
// when the button's clicked (external)
let internalChangeCount = 0;
let externalChangeCount = 0;
// Change event handler
// The SliderChangeEvent type is a convenient alias
// to ValueChangeEvent<number>
function onChange(event: SliderChangeEvent) {
// Identify where the event came from, 'internal' or 'external'
event.detail.origin === 'internal'
? internalChangeCount++
: externalChangeCount++;
}
// A Svelte reactive statement is (usually) a much better way to respond
// to value changes! $: console.log(speed);
</script>
<Slider
bind:value={speed}
min={0}
max={100}
on:change={onChange}
label="Set Speed Limit:"
/>
<Monitor
value={internalChangeCount}
format={(v) => v.toFixed(0)}
label="Internal change events:"
/>
<Monitor
value={externalChangeCount}
format={(v) => v.toFixed(0)}
label="External change events:"
/>
<Button
on:click={() => (speed = 55)}
label="Change limit externally:"
title="Limit: 55"
/>

Wide sliders

๐Ÿ”—

Hiroki Kokubunโ€™s CameraKit plugin includes a wide option on its<Ring> and <Wheel> controls to optionally hide the numeric input text field.

This came up in an issue, and is also a nice idea in general, so support has been added to the <Slider> and <IntervalSlider> components in Svelte Tweakpane UI:

See example code
SvelteTweakpaneWideSlideExample.svelte
<script lang="ts">
import {
Checkbox,
IntervalSlider,
Ring,
Separator,
Slider,
Stepper,
Wheel
} from 'svelte-tweakpane-ui';
let min = 0;
let max = 100;
let value = 50;
let wide = true;
</script>
<Checkbox bind:value={wide} label="Wide" />
<Separator />
<Slider bind:value {min} {max} label="Slider" {wide} />
<Stepper bind:value {min} {max} label="Stepper" step={10} {wide} />
<IntervalSlider
value={[min, max]}
{min}
{max}
bind:meanValue={value}
label="IntervalSlider"
{wide}
/>
<Wheel bind:value {min} {max} label="Wheel" {wide} />
<Ring bind:value {min} {max} label="Ring" {wide} />

Differences

๐Ÿ”—

Certain aspects of the Tweakpane API donโ€™t make a ton of sense in the Svelte context, and have been removed or hidden from the API.

Custom containers

๐Ÿ”—

The container PaneConfig option is not exposed, because correct placement in the containing DOM is managed by Svelte Tweakpane UI, and <Pane position="inline" ...> may be used where youโ€™d like a pane to become part of the normal document flow.

Visibility

๐Ÿ”—

The hidden / visibility accessor is not exposed, because visibility a pane and its components may be managed directly in Svelte by adding / removing elements from the Svelte component markup through {#if} conditionals and similar.

index is not exposed. The order of controls appearance matches their position in the Svelte component markup.

Disposal

๐Ÿ”—

Svelte Tweakpane UI full manages the lifecycle of the underlying Tweakpane objects, obviating the need for manual calls to dispose.

Import / export state

๐Ÿ”—

Abstractions around importState() and exportState() are not yet implemented. For now, Svelte provides many ways to load and persist values (stores, etc.).

Plugins

๐Ÿ”—

A curation of first- and third-party Tweakpane Plugins have been wrapped in components and bundled with Svelte Tweakpane UI. These plugins are automatically registered on demand, and work just like other components.

Tab rename

๐Ÿ”—

The vanilla Tweakpane Tab is referred to as a <TabGroup> in Svelte Tweakpane UI, and the vanilla Tweakpane Page is referred to as a <TabPage>.

Params become props

๐Ÿ”—

The Vanilla Tweakpane API organizes control configuration into Params interfaces and objects. Svelte Tweakpane UI pushes these values up into top-level props on each component.