New in Sketch 2025.1
Important: Athens (2025.1) introduced fundamental changes to Sketch. API documentation may not be up to date.
We’ve released Sketch 2025.1 Athens on May 27, 2025. Below you will find an overview of the API changes made in this release, and also a few tips and tricks to get you started with the new features.
Migrating from Artboards to Frames and Graphics
In Athens two new types of layer containers were introduced: Frames and Graphics — which replaced Artboards. Since all containers are now mere layer groups with a specific layout behavior, in order to distinguish one from another don’t rely on just their type
alone, but inspect the new groupBehavior
property instead:
const { Group, GroupBehavior } = require('sketch/dom');
const group = // ...
if (group.groupBehavior === GroupBehavior.Frame) {
// a Frame
} else if (group.groupBehavior === GroupBehavior.Graphic) {
// a Graphic
} else if {
// a regular layer group
}
Note that both Frames and Graphics will still report Artboard
as their type for backwards compatibility:
const { sketch } = require('sketch/dom');
const group = // ...
if (group instanceof sketch.Artboard) {
// could be a Frame, or a Graphic,
// or an Artboard (in previous versions of Sketch)
}
In similar fashion, calling the getParentArtboard()
function on a layer will return its enclosing top-level container.
Iterating Containers
One major difference between legacy Artboards and new Frame and Graphic containers is that the latter can be nested. This presents a challenge of differentiating any top-level containers (that might play the role of a standalone design components like individual UI screens) — from nested containers, usually just grouping lower-level design elements.
For instance, to find all top-level containers on the given Page
, you might iterate its layers
array directly:
function findTopLevelContainersOnPage(page) {
return page.layers.filter((layer) => layer instanceof sketch.Artboard)
}
or take advantage of the find
API:
function findTopLevelContainersOnPage(page) {
return sketch.find('Artboard', page)
}
In order to access the second-level containers, feel free to iterate the parent container’s layers
array and so forth:
const page = // ...
findTopLevelContainersOnPage(page).forEach((root) => {
const secondLevels = root.layers.filter((layer) => {
return layer.groupBehavior !== undefined
})
// ...
})
sketch.find()
The find
API is a great fit if you need to quickly iterate a large layer hierarchy to find a specific layer, or multiple layers matching specific queries:
// To find a top-level container with the given identifier in the whole document
const id = 'XXX-YYY-ZZZ...'
const container = sketch.find(`Artboard, #${id}`)[0]
// To find all nested containers (children of the given one) matching the given name
const marker = '[export]'
const containers = sketch.find(`Group, [name*='${marker}']`, parentContainer)
// To find all currently selected top-level containers on the given page
const selection = sketch.find(`Artboard, [selected=true]`)
In case you want to include the parent container itself if it matches the given predicate, pass the inclusive
flag:
// Will return all visible sublayers of `root`, including `root` itself if it's visible
sketch.find('[hidden=false]', root, { inclusive: true })
Sizing and Layout
Inside new containers, layers now have standardized sizing and pinning options. Accessing and modifying these options from a plugin is done via the following new APIs.
Layer Sizing via Layer.horizontalSizing
and Layer.verticalSizing
.
These properties can be set to either Fixed
, Fit
, Fill
, or Relative
:
const { FlexSizing } = require('sketch/dom')
switch (layer.horizontalSizing) {
case FlexSizing.Fixed:
// The layer determines its own size along the horizontal axis,
// but other properties may override it (see the article linked above)
break
case FlexSizing.Fit:
// The layer hugs its children or contents along the horizontal axis.
// Available for Stacks and text layers
break
case FlexSizing.Fill:
// The layer fills the available horizontal space in the parent container.
// Available to layers inside Stacks
break
case FlexSizing.Relative:
// The layer is sized proportionally relative to its parent
// along the horizontal axis. When its parent resizes, it does too
break
}
layer.verticalSizing = FlexSizing.Relative
Note that not all FlexSizing options are available for all layers at all times — see “Sizing options for frame contents” for details.
Layer Pinning via Layer.horizontalPins
, Layer.verticalPins
.
These properties can each be set to either None
, Min
, Max
, or Both
— with Min and Max corresponding to either the left and right edges, or top and bottom edges depending on the chosen axis:
const { Pin } = require('sketch/dom')
switch (layer.verticalPins) {
case Pin.None:
// neither top nor bottom edge is pinned
break
case Pin.Min:
// the top edge is pinned
break
case Pin.Max:
// the bottom edge is pinned
break
case Pin.Both:
// both top and bottom edges are pinned
break
}
Both horizontalPins
and verticalPins
are bitmasks, which means that in order to query whether a specific edge is pinned, you need to use the bitwise AND operator — defined as single &
in JavaScript (not to be confused with a double &&
for the logical AND):
if (layer.verticalPins & Pin.Min) {
// The top edge is pinned
// (the bottom edge might be pinned too, but we don't care)
}
In order to pin edges yourself, you may either assign an entire new value for the desired axis:
// Leave only the right edge pinned
// (this will pin the right edge *and* unpin the left one if pinned)
layer.horizontalPins = Pin.Max
or you may toggle individual edges via the bitwise OR and AND operators – to add or remove certain pins respectively:
// Pin the left edge. Other already pinned edges remain intact:
layer.horizontalPins |= Pin.Min
// Unpin the left edge. Other pinned edges remain intact:
layer.horizontalPins &= ~Pin.Min
The ~
operator used in the last example negates the Pin.Min
value, transforming it into “everything BUT the Pin.Min” value. Bitwise operations are cool like that.
Note that even though you can pin any edge of any layer via the API, Pins will only have effect on layers that either:
- belong to a
Frame
, or- belong to a regular
Group
nested in some other container (i.e. not a page-levelGroup
).
Styling Containers
Unlike Artboards, Frames and Graphics support the full range of styling options available to most Sketch layers: borders, fills, shadows, and even blur.
Styling these new containers is no different than styling any other StyledLayer
:
const { Style } = require('sketch/dom')
let graphic = // ...
(graphic.style.fills = [
{
color: '#c0ffee',
fillType: sketch.Style.FillType.Color,
thickness: 5,
},
])
graphic.style.borderOptions = {
dashPattern: [20, 5, 20, 5],
}
The legacy Artboard.background
property, which remains intact for backwards compatibility, now acts as a mere proxy for the fills
array: by adding or removing fills from the receiver container as necessary.
Other Notable API Changes
Added an option to specify the output filename in export()
Now you may specify the destination filename directly via the filename
option:
const targetDirectory = '/path/to/output/folder'
const filename = 'an-arbitrary-file-name.png'
sketch.export(layer, {
output: targetDirectory,
filename: filename,
formats: ['png'],
})
const exportedImagePath = [targetDirectory, filename].join('/')
Renamed Style.blur
to Style.blurs
This uniforms the Style
API surface, as all other style parts are already plural: fills
, borders
, shadows
. The new Style.blurs
array will contain either one or zero Blur
objects.
Added Shadow.isInnerShadow
Use this new property to distinguish an inner shadow from a drop shadow.
Removed MSGroup.children()
This internal Sketch method was used to collect all container’s children layers recursively (i.e. including grandchildren, grand-grandchildren and so on).
The following function will quickly list all children layers of the given container:
function childrenOf(container) {
return sketch.find('*', container)
}
// Works on any layer container:
childrenOf(frame)
childrenOf(graphic)
childrenOf(page)
childrenOf(group)
childrenOf(shapeGroup)
Removed MSPage.currentArtboard()
This internal Sketch method was used to identify the artboard containing the currently selected layer (or, in case there are multiple selected layers, an artboard containing the first one).
The following function will return all top-level containers (Frames/Graphics/Artboards) that either:
- have at least one children layer selected, or
- are selected themselves
function topLevelContainersWithSelection(page) {
return page.selectedLayers.reduce((prev, layer) => {
// Include all explicitly selected top-level containers
if (layer instanceof sketch.Artboard) {
return prev.concat(layer);
}
// Otherwise try to reach this layer's top-level container if one exists
// (i.e. this layer does not lay directly on the page)
return prev.concat(layer.getParentArtboard() ?? []);
}, []);
}
let page = // ...
const currentArtboard = topLevelContainersWithSelection(page)[0];
Removed MSDocument.artboards()
, MSDocument.hasArtboards()
, and similar methods
Consider using the find
function from the JavaScript API:
const { find, Document, Page } = require("sketch/dom");
const nativeMSDocumentInstance = // ...
const document = Document.from(nativeMSDocumentInstance);
const artboards = find("Artboard", document);
// or, in case of MSPage:
const nativeMSPageInstance = // ...
const page = Page.from(nativeMSPageInstance);
const artboards = find("Artboards", page);
Removed MSPage.artboardWithID()
, and MSPage.artboardNamed()
methods
Consider using find
:
const id = 'XX-ZZZ-YY'
const artboardWithSaidID = find(`Artboard, #${id}`, page) // Note the # symbol before the identifier!
const name = 'XYZ'
const firstArtboardWithSaidName = find(`Artboard, [name=${name}]`, page)
// As far as `name` goes, find() can also match:
// a full string but ignoring case:
find(`Artboard, [name~=${nAmE}]`)
// a substring
find(`Artboard, [name*=${substring}]`)
// (and case-insensitive substring)
find(`Artboard, [name~*=${sUbStTiNg}]`)
// a prefix
find(`Artboard, [name^=${prefix}]`)
// a suffix
find(`Artboard, [name$=${suffix}]`)
Deprecating Document.ColorSpace.Unmanaged
In Sketch version 90 and earlier, the default color profile was set to Unmanaged, which meant we’d use your display’s settings but export as sRGB. From version 91 onwards, we’ve removed the Unmanaged option. All documents that previously used this profile now use sRGB by default.
Document.changeColorSpace()
and related APIs are still available for converting documents between sRGB and P3 color profiles.