Customizing Selection Appearance and Behavior in Fabric.js
When an object is selected on a Fabric.js canvas, its visual representation changes. This includes the appearance of control handles, the selection border, and other interactive states. This guide covers the properties and methods available to customize this selection state.
Initial Setup
First, create a basic canvas and add a shape to work with.
<canvas id="myCanvas" style="border: 1px solid #ccc;"></canvas>
<script>
const canvas = new fabric.Canvas('myCanvas', {
width: 400,
height: 400,
})
const ellipse = new fabric.Ellipse({
top: 80,
left: 80,
rx: 60, // Horizontal radius
ry: 40, // Vertical radius
fill: '#a8d8ea'
})
canvas.add(ellipse)
</script>
Control Handles (Corners)
Control handles are the interactive points that appear around a selected object, used for scaling and rotating.
Solid vs. Hollow Handles
By default, control handles are hollow (transparent). To make them solid, set the transparentCorners property to false.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
transparentCorners: false // Handles are now solid
})
Handle Color
Use the cornerColor property to set the fill color of the control handles.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
transparentCorners: false,
cornerColor: 'green' // Solid green handles
})
Handle Stroke Color
To set the border color of the handles independently, use the cornerStrokeColor property.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
transparentCorners: false,
cornerColor: 'green',
cornerStrokeColor: 'darkblue' // Blue border on green handles
})
Handle Size
Adjust the size of the control handles with the cornerSize property.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
cornerSize: 18 // Larger handles
})
Handle Border Dash Pattern
Create dashed borders for the control handles using the cornerDashArray property. It accepts an array of numbers defining the dash pattern.
[5]: Equal dash and gap length.[5, 10]: 5px dash, 10px gap.[5, 10, 15]: 5px dash, 10px gap, 15px dash, 5px gap, 10px dash... (repeats).
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
cornerSize: 18,
cornerDashArray: [5, 10] // Dashed border pattern
})
Handle Shape
Change the handle shape from square to circle using the cornerStyle property.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
cornerStyle: 'circle' // Circular handles
})
Selection Border (Bounding Box)
The rectangular border that appears around a selected object is often called the selection border or bounding box.
Border Color
Set the color of the selection border with the borderColor property.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
borderColor: 'purple' // Purple selection border
})
Border Thickness
Control the thickness of the selection border using the borderScaleFactor property. The base border width is multiplied by this value.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
borderScaleFactor: 3 // Thicker border
})
Border Dash Pattern
Similar to control handles, the selection border can also be dashed using the borderDashArray property.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
borderDashArray: [15, 5, 3, 5] // Complex dash pattern
})
Additional Styling
Padding
Internal padding can be added between the object's visual bounds and the selection border/control handles using the padding property.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
padding: 25 // Increased space between object and selection UI
})
Background Colors
Fabric.js distinguishes between fill color and background color. The backgroundColor property fills the rectangular area the object occupies (its bounding box). The selectionBackgroundColor fills the area between the object and the selection border, which is only visible when padding is applied.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
backgroundColor: 'lightgray', // Fills the object's bounding box area
padding: 20,
selectionBackgroundColor: 'rgba(0, 200, 0, 0.3)' // Green tint in padded area when selected
})
Opacity During Movement
Reduce the opacity of the selection UI (handles and border) while the object is being dragged using borderOpacityWhenMoving. Accepts a value from 0 (transparent) to 1 (opaque).
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
borderOpacityWhenMoving: 0.3 // Very faint selection UI while moving
})
Selection State and Behavior
Disabling Selection
Prevent an object from being seelcted entirely by setting selectable to false.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
selectable: false // Cannot be clicked to select
})
Pixel-Perfect Selection
By default, clicking anywhere within an object's rectangular bounding box will select it. For non-rectangular shapes (like circles), this includes "empty" corners. Setting perPixelTargetFind to true restricts selection to the actual painted pixels of the object.
const circle = new fabric.Circle({
radius: 50,
fill: 'red',
perPixelTargetFind: true // Must click on the red circle itself
})
Hiding Control Handles
Hide all control handles by setting hasControls to false. This prevents scaling and rotation via handles.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
hasControls: false // No handles visible
})
Hiding the Selection Border
Hide the selection border by setting hasBorders to false.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
hasBorders: false // No border visible when selected
})
Controlling Individual Handle Visibility
You can show or hide specific control handles. The handles are identified by keys: tl (top-left), tr (top-right), br (bottom-right), bl (bottom-left), ml (middle-left), mt (middle-top), mr (middle-right), mb (middle-bottom), mtr (middle-top for rotation).
Use setControlVisible(controlKey, visible) for a single handle, or setControlsVisibility(options) for multiple handles.
const rect = new fabric.Rect({
width: 100,
height: 100,
fill: 'orange',
})
// Hide the top-left and bottom-right handles
rect.setControlsVisibility({
tl: false,
br: false
})
// Alternatively, hide the bottom-left handle individually
rect.setControlVisible('bl', false)
Checking Handle Visibility
Use isControlVisible(controlKey) to check if a specific handle is currently visible.
rect.setControlVisible('tl', false)
console.log(rect.isControlVisible('tl')) // false
console.log(rect.isControlVisible('tr')) // true (default)
Retrieving the Currently Selected Object
Use canvas methods to get the active selection.
canvas.getActiveObject(): Returns the single currently active object, ornull.canvas.getActiveObjects(): Returns an array of all currently selected objects (useful for multi-selection), or an empty array.
// Example: Change fill color of the selected object
canvas.on('selection:created', function() {
const activeObj = canvas.getActiveObject()
if (activeObj) {
activeObj.set('fill', 'cyan')
canvas.renderAll()
}
})