Features
A handful of additional features have been implemented in the Svelte layer of the project.
Additions
Section titled “Additions”Draggability
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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)
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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
<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
Section titled “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
<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
Section titled “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
Section titled “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
Section titled “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
Section titled “Disposal”Svelte Tweakpane UI full manages the lifecycle of the underlying Tweakpane objects, obviating the need for manual calls to dispose.
Import / export state
Section titled “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
Section titled “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
Section titled “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
Section titled “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.