Paint Format

Copy formatting from one cell or range and apply it to another

The Paint Format feature, also known as Format Painter, allows users to copy formatting from one cell or range and apply it to another location. This is useful for quickly applying consistent formatting across your spreadsheet.

Overview

Paint Format copies all visual formatting from the source cells (colors, borders, fonts, alignment, number formats, etc.) and applies it to target cells, without affecting the cell values.

Basic Usage

Using the Toolbar Button

The easiest way to use Paint Format is through the ButtonPaintFormat toolbar button:

import {
  SpreadsheetProvider,
  CanvasGrid,
  Toolbar,
  ButtonPaintFormat,
} from "@rowsncolumns/spreadsheet";
import { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state";

function MySpreadsheet() {
  const {
    activeCell,
    activeSheetId,
    selections,
    onSavePaintFormat,
    isPaintFormatActive,
    // ... other hook values
  } = useSpreadsheetState({
    sheets,
    sheetData,
    onChangeSheets,
    onChangeSheetData,
  });

  return (
    <SpreadsheetProvider>
      <Toolbar>
        <ButtonPaintFormat
          isActive={isPaintFormatActive}
          onClick={() =>
            onSavePaintFormat(activeSheetId, activeCell, selections)
          }
        />
      </Toolbar>
      <CanvasGrid
        sheetId={activeSheetId}
        activeCell={activeCell}
        selections={selections}
        // ... other props
      />
    </SpreadsheetProvider>
  );
}

How It Works

1. Copy Format (Activate Paint Format)

Click the Paint Format button or call onSavePaintFormat to copy formatting from the currently selected cells:

// Save formatting from current selection
onSavePaintFormat(activeSheetId, activeCell, selections);

When paint format is active, isPaintFormatActive returns true, which can be used to show visual feedback.

2. Apply Format

Once activated, simply select the target cells where you want to apply the formatting. The spreadsheet automatically applies the copied formatting to the new selection.

3. Deactivate

Paint format automatically deactivates after applying to one selection. To cancel without applying, click the Paint Format button again.

Programmatic Usage

You can also use paint format programmatically:

import { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state";

const {
  onSavePaintFormat,
  onApplyPaintFormat,
  isPaintFormatActive,
  paintFormat, // Direct function to paint from one range to another
} = useSpreadsheetState({
  // ... configuration
});

// Copy formatting from range A1:B2
onSavePaintFormat(
  1, // sheetId
  { rowIndex: 1, columnIndex: 1 }, // activeCell
  [{
    range: {
      startRowIndex: 1,
      endRowIndex: 2,
      startColumnIndex: 1,
      endColumnIndex: 2,
    }
  }]
);

// Or paint directly from one range to another
paintFormat(
  {
    startRowIndex: 1,
    endRowIndex: 2,
    startColumnIndex: 1,
    endColumnIndex: 2,
    sheetId: 1,
  },
  {
    startRowIndex: 5,
    endRowIndex: 6,
    startColumnIndex: 3,
    endColumnIndex: 4,
    sheetId: 1,
  }
);

What Gets Copied

Paint Format copies the following formatting properties:

  • Text formatting: Font family, font size, bold, italic, underline, strikethrough

  • Colors: Text color, background color

  • Borders: All border styles and colors

  • Alignment: Horizontal and vertical alignment

  • Number formats: Currency, percentage, date, custom formats

  • Text wrapping: Wrap, overflow, or clip

  • Indentation: Text indentation levels

What Does NOT Get Copied

Paint Format does NOT copy:

  • Cell values or formulas

  • Cell comments/notes

  • Data validation rules

  • Conditional formatting rules

  • Protected range settings

  • Merged cell configuration

Complete Example

import React, { useState } from "react";
import {
  SpreadsheetProvider,
  CanvasGrid,
  Toolbar,
  ButtonPaintFormat,
  ToolbarSeparator,
  ButtonBold,
  ButtonItalic,
  BackgroundColorSelector,
} from "@rowsncolumns/spreadsheet";
import {
  useSpreadsheetState,
  type SheetData,
} from "@rowsncolumns/spreadsheet-state";

function SpreadsheetWithPaintFormat() {
  const [sheets, setSheets] = useState([
    { sheetId: 1, rowCount: 100, columnCount: 26, title: "Sheet 1" }
  ]);
  const [sheetData, setSheetData] = useState<SheetData>({});

  const {
    activeCell,
    activeSheetId,
    selections,
    getCellData,
    getEffectiveFormat,
    onChangeActiveCell,
    onChangeSelections,
    onChangeFormatting,
    onSavePaintFormat,
    isPaintFormatActive,
  } = useSpreadsheetState({
    sheets,
    sheetData,
    onChangeSheets: setSheets,
    onChangeSheetData: setSheetData,
  });

  const currentCellFormat = getEffectiveFormat(
    activeSheetId,
    activeCell.rowIndex,
    activeCell.columnIndex
  );

  return (
    <SpreadsheetProvider>
      <Toolbar>
        <ButtonBold
          isActive={currentCellFormat?.textFormat?.bold}
          onClick={() =>
            onChangeFormatting(
              activeSheetId,
              activeCell,
              selections,
              "textFormat",
              { bold: !currentCellFormat?.textFormat?.bold }
            )
          }
        />
        <ButtonItalic
          isActive={currentCellFormat?.textFormat?.italic}
          onClick={() =>
            onChangeFormatting(
              activeSheetId,
              activeCell,
              selections,
              "textFormat",
              { italic: !currentCellFormat?.textFormat?.italic }
            )
          }
        />
        <BackgroundColorSelector
          color={currentCellFormat?.backgroundColor}
          onChange={(color) =>
            onChangeFormatting(
              activeSheetId,
              activeCell,
              selections,
              "backgroundColor",
              color
            )
          }
        />
        <ToolbarSeparator />
        <ButtonPaintFormat
          isActive={isPaintFormatActive}
          onClick={() =>
            onSavePaintFormat(activeSheetId, activeCell, selections)
          }
        />
      </Toolbar>
      <CanvasGrid
        sheetId={activeSheetId}
        activeCell={activeCell}
        selections={selections}
        getCellData={getCellData}
        onChangeActiveCell={onChangeActiveCell}
        onChangeSelections={onChangeSelections}
      />
    </SpreadsheetProvider>
  );
}

Keyboard Shortcut

Paint Format can also be activated via keyboard shortcuts (implementation dependent on your configuration):

// Example: Activate paint format with Ctrl+Shift+C (copy format)
// Then apply with Ctrl+Shift+V (paste format)

Use Cases

Consistent Table Headers

Apply the same header formatting to multiple tables:

  1. Format one header cell (bold, background color, borders)

  2. Click Paint Format

  3. Select other header cells to apply the same style

Standardizing Reports

Quickly apply consistent formatting across similar data sections:

  1. Format one complete section

  2. Use Paint Format to copy it

  3. Apply to other sections

Color Coding

Apply color coding patterns to categorize data:

  1. Set up one cell with specific colors

  2. Paint format to similar categories

Best Practices

  1. Format once, apply many: Create template cells with desired formatting, then use Paint Format to replicate

  2. Visual feedback: The isPaintFormatActive state should be used to provide visual indication that paint format mode is active

  3. Undo support: Paint format operations are tracked in undo history

  4. Performance: Paint format is efficient even for large ranges

API Reference

useSpreadsheetState Returns

Property
Type
Description

onSavePaintFormat

(sheetId, activeCell, selections) => void

Saves formatting from selection for painting

onApplyPaintFormat

(sheetId, activeCell, selections) => void

Applies saved formatting to new selection

isPaintFormatActive

boolean

Whether paint format mode is active

paintFormat

(sourceRange, targetRange) => void

Directly paint from one range to another

Limitations

  • Paint format is a client-side operation and works with the current spreadsheet state

  • Very large ranges may take a moment to process

  • Formatting from merged cells requires special handling

Troubleshooting

Paint Format Not Working

Ensure you have the necessary callbacks:

const {
  onSavePaintFormat,
  isPaintFormatActive,
  // These are required for paint format to work
  onChangeFormatting,
  getEffectiveFormat,
} = useSpreadsheetState({
  // configuration
});

Visual Feedback Not Showing

Use isPaintFormatActive to style the button:

<ButtonPaintFormat
  isActive={isPaintFormatActive}  // This provides visual feedback
  onClick={handlePaintFormat}
/>

Last updated

Was this helpful?