Work with multiple measurement units including pixels, millimeters, inches, centimeters, and points for both print and digital design workflows.
The Designer package includes a comprehensive unit system that supports multiple measurement scales beyond pixels. This allows you to work in your preferred units, whether designing for print (mm, inches) or digital (pixels, points), while maintaining precision and consistency throughout the design process.
Supported Units
Unit | Symbol | Description | Common Use Case |
---|---|---|---|
Pixels | px | Screen pixels | Web design, UI |
Millimeters | mm | Metric measurement | Print design, Europe |
Inches | in | Imperial measurement | Print design, US |
Centimeters | cm | Metric measurement | Large print formats |
Points | pt | Typographic points (1/72 inch) | Typography, print |
Key Features
- Native Unit Storage: Values are stored with their original units (e.g., "100mm") ensuring exports maintain correct measurements.
- DPI-Aware Conversion: Supports different DPI settings for screen (96 DPI) and print (300 DPI) contexts.
- Backwards Compatible: Existing pixel-based designs continue to work without modification.
- Real-time Conversion: Switch between units on the fly with automatic conversion.
- Precision: All converted values use appropriate decimal places for clean display.
Basic Setup
Configure the Designer component with your preferred units:
import { Designer } from "@shadcn/designer"
function PrintDesigner() {
return (
<Designer
// Frame size in millimeters
frameSize={{ width: 210, height: 297, unit: "mm" }}
// Display values in millimeters
unitSystem="mm"
// High DPI for print
dpi={300}
defaultLayers={[]}
>
{/* Designer content */}
</Designer>
)
}
Frame Size with Units
The frameSize
prop now accepts an optional unit
field:
// A4 paper in millimeters
frameSize={{ width: 210, height: 297, unit: "mm" }}
// US Letter in inches
frameSize={{ width: 8.5, height: 11, unit: "in" }}
// Screen size in pixels (default)
frameSize={{ width: 1920, height: 1080 }} // unit defaults to "px"
Hooks
useUnitSystem
Returns the current unit system being used for display.
import { useUnitSystem } from "@shadcn/designer"
function MyComponent() {
const unitSystem = useUnitSystem() // "px" | "mm" | "in" | "cm" | "pt"
return <div>Current unit: {unitSystem}</div>
}
useSetUnitSystem
Sets the unit system for displaying values.
import { useSetUnitSystem } from "@shadcn/designer"
function UnitSwitcher() {
const setUnitSystem = useSetUnitSystem()
return (
<button onClick={() => setUnitSystem("mm")}>
Switch to Millimeters
</button>
)
}
useDPI
Returns the current DPI setting.
import { useDPI } from "@shadcn/designer"
function DPIDisplay() {
const dpi = useDPI() // Default: 96
return <div>Current DPI: {dpi}</div>
}
useSetDPI
Sets the DPI for unit conversions.
import { useSetDPI } from "@shadcn/designer"
function DPISwitcher() {
const setDPI = useSetDPI()
return (
<select onChange={(e) => setDPI(Number(e.target.value))}>
<option value="96">Screen (96 DPI)</option>
<option value="300">Print (300 DPI)</option>
</select>
)
}
Utility Functions
All unit utility functions are available from @shadcn/designer/utils
:
toPixels
Converts any unit value to pixels.
import { toPixels } from "@shadcn/designer/utils"
// Convert 25.4mm to pixels at 96 DPI
const dpi = 96
const pixels = toPixels(25.4, "mm", dpi) // 96 pixels (1 inch)
// Convert 72 points to pixels at 96 DPI
const pixels2 = toPixels(72, "pt", dpi) // 96 pixels
fromPixels
Converts pixels to a target unit.
import { fromPixels } from "@shadcn/designer/utils"
// Convert 96 pixels to millimeters at 96 DPI
const dpi = 96
const mm = fromPixels(96, "mm", dpi) // 25.4mm
// Convert 300 pixels to inches at 300 DPI
const printDpi = 300
const inches = fromPixels(300, "in", printDpi) // 1 inch
convertUnit
Converts a value from one unit to another.
import { convertUnit } from "@shadcn/designer/utils"
// Convert 100mm to inches at 300 DPI
const printDpi = 300
const inches = convertUnit(100, "mm", "in", printDpi) // ~3.94 inches
// Convert 2 inches to pixels at 96 DPI
const screenDpi = 96
const pixels = convertUnit(2, "in", "px", screenDpi) // 192 pixels
parseValueWithUnit
Parses a string value with unit into its components.
import { parseValueWithUnit } from "@shadcn/designer/utils"
const parsed = parseValueWithUnit("100mm")
// Returns: { value: 100, unit: "mm" }
const parsed2 = parseValueWithUnit("2.5in")
// Returns: { value: 2.5, unit: "in" }
// Numbers without units default to pixels
const parsed3 = parseValueWithUnit("200")
// Returns: { value: 200, unit: "px" }
Additional Utilities
import {
valueToPixels, // Convert "100mm" string to pixels
pixelsToValue, // Convert pixels to "100mm" string
formatValue, // Format with appropriate precision
getUnitDisplayName, // Get full name ("Millimeters")
getUnitShortName, // Get abbreviation ("mm")
roundForUnit, // Round to unit's precision
DEFAULT_DPI, // 96 (CSS standard)
DPI_PRESETS // { screen: 96, print: 300, retina: 192 }
} from "@shadcn/designer/utils"
Unit Selector Component
Add a unit selector to your toolbar for easy switching:
import {
ActionUnitSelector,
DesignerToolbar,
DesignerToolbarGroup
} from "@shadcn/designer"
function MyToolbar() {
return (
<DesignerToolbar>
<DesignerToolbarGroup>
<ActionUnitSelector />
</DesignerToolbarGroup>
</DesignerToolbar>
)
}
Layer Storage
Layers store values with their original units, preserving precision:
const layer: Layer = {
id: "1",
name: "Business Card",
type: "frame",
value: "",
cssVars: {
// Dimensions in millimeters
"--width": "85mm",
"--height": "55mm",
"--translate-x": "10mm",
"--translate-y": "10mm",
// Border in points
"--border-width": "1pt",
// Font size in points
"--content-font-size": "12pt",
// Mixed units are supported
"--padding-top": "5mm",
"--margin-left": "0.25in",
}
}
Automatic Conversion
When switching units, values are converted for display but stored in their original units:
- Layer stores:
"--width": "100mm"
- User switches to inches
- Display shows: 3.94"
- Internally still stored as: "100mm"
- Export preserves: "100mm"
Understanding DPI
DPI (Dots Per Inch) affects how physical units convert to pixels:
- 96 DPI (Screen): 1 inch = 96 pixels (CSS standard)
- 300 DPI (Print): 1 inch = 300 pixels (print quality)
Conversion Examples
// At 96 DPI (screen)
const screenDpi = 96
toPixels(1, "in", screenDpi) // 96px
toPixels(25.4, "mm", screenDpi) // 96px (25.4mm = 1 inch)
// At 300 DPI (print)
const printDpi = 300
toPixels(1, "in", printDpi) // 300px
toPixels(25.4, "mm", printDpi) // 300px
Precision and Rounding
All unit conversions use appropriate precision for clean display:
- Pixels: Always rounded to integers
- Points: 1 decimal place
- Millimeters/Centimeters/Inches: 2 decimal places
This ensures values like "100.00mm" display as "100mm" while maintaining precision where needed.
Dynamic Unit Switching
"use client"
import { useState } from "react"
import { Designer } from "@shadcn/designer"
import type { Unit } from "@shadcn/designer/utils"
function DesignerWithUnitToggle() {
const [unitSystem, setUnitSystem] = useState<Unit>("px")
const [dpi, setDPI] = useState(96)
return (
<div>
<div className="controls">
<select
value={unitSystem}
onChange={(e) => setUnitSystem(e.target.value as Unit)}
>
<option value="px">Pixels</option>
<option value="mm">Millimeters</option>
<option value="in">Inches</option>
</select>
<select
value={dpi}
onChange={(e) => setDPI(Number(e.target.value))}
>
<option value="96">Screen (96 DPI)</option>
<option value="300">Print (300 DPI)</option>
</select>
</div>
<Designer
unitSystem={unitSystem}
dpi={dpi}
defaultLayers={[]}
>
{/* Designer content */}
</Designer>
</div>
)
}
Migration Guide
For Existing Projects
Existing projects using pixels will continue to work without any changes:
- No Breaking Changes: All existing pixel-based layers work as before
- Optional Upgrade: Add unit support when needed
- Gradual Migration: Mix pixel and unit-based layers
Adding Unit Support
To add unit support to an existing project:
// Before (pixels only)
<Designer defaultLayers={layers}>
{/* content */}
</Designer>
// After (with unit support)
<Designer
defaultLayers={layers}
unitSystem="px" // Start with pixels
dpi={96} // Screen DPI
>
<DesignerHeader>
<ActionUnitSelector /> {/* Add unit switcher */}
</DesignerHeader>
{/* content */}
</Designer>
Converting Existing Layers
To convert existing pixel values to units:
import { pixelsToValue } from "@shadcn/designer/utils"
// Convert existing pixel layer to use millimeters
const dpi = 96
const convertedLayer = {
...existingLayer,
cssVars: {
...existingLayer.cssVars,
// Convert 400px to mm at 96 DPI
"--width": pixelsToValue(400, "mm", dpi), // "105.83mm"
"--height": pixelsToValue(300, "mm", dpi), // "79.38mm"
}
}
Best Practices
- Choose Appropriate Units: Use mm/inches for print, pixels for web
- Set Correct DPI: 96 for screen, 300+ for print
- Store Native Units: Let layers store their original units
- Consistent Units: Use the same unit type within a design
- Test Exports: Verify exported values maintain correct units
Troubleshooting
Common Issues
Q: Why do my values change when switching units?
A: Values are converted for display but stored in original units. The visual change is expected.
Q: How do I ensure accurate print dimensions?
A: Use the appropriate DPI (300+) and native print units (mm/inches).
Q: Can I mix different units in one design?
A: Yes, each layer property can use different units as needed.
Q: What happens to units when exporting?
A: Exported values maintain their original units without conversion.
API Reference
Types
type Unit = "px" | "mm" | "in" | "cm" | "pt"
interface ValueWithUnit {
value: number
unit: Unit
}
interface FrameSize {
width: number
height: number
unit?: Unit // Optional, defaults to "px"
}
Constants
const DEFAULT_DPI = 96
const DPI_PRESETS = {
screen: 96,
print: 300,
retina: 192,
}
Supported Dimension Properties
The following CSS variable properties automatically convert between units:
- Position:
--translate-x
,--translate-y
- Size:
--width
,--height
- Spacing:
--padding-*
,--margin-*
- Border:
--border-*-width
,--border-*-radius
- Typography:
--font-size
,--letter-spacing
,--line-height
- Effects:
--box-shadow-*
,--text-shadow-*
,--filter-blur
- Content variants:
--content-font-size
,--content-letter-spacing
, etc.