Forum Discussion
RH
You can use the Format Painter tool to copy the cell format
but similar to the FILL color button you have to hit it each time so AFAIK a 'locked on' functionality for the Fill (or other excel functions) is not possible with existing excel functionality. However, this can be achieved using either a macro or a script. Because (IMHO) things are moving away from macros, here is the code for a script that will use the currently selected cell color and then highlight every other cell you click on that same color until you click on that original cell again ...
function main(workbook: ExcelScript.Workbook) {
// Get the active cell and worksheet.
let selectedCell = workbook.getActiveCell();
let selectedSheet = workbook.getActiveWorksheet();
const origCell = selectedCell.getAddress();
const selectedColor = selectedCell.getFormat().getFill().getColor();
while (selectedCell.getAddress() == origCell) {
selectedCell = workbook.getActiveCell();
}
while (selectedCell.getAddress() != origCell) {
// Set fill color to yellow for the selected cell.
selectedCell.getFormat().getFill().setColor(selectedColor);
selectedCell = workbook.getActiveCell();
}
}to add this click on the Automate menu item -> New Script -> Create in Code Editor
Highlight existing code and replace with the above. Click on the pencil to rename the script to whatever you want to call it. and then click save.
You then have the option to either just click on the run button from this automate menu window or you can add a button to the worksheet.
OK I updated the script to a) allow you to select and highlight ranges and b) to 'mark' the original cell using a grid pattern to make it easier to find and re-click it to end the script:
function main(workbook: ExcelScript.Workbook) {
// Get the active cell and worksheet.
let selectedCell = workbook.getActiveCell();
let selectedSheet = workbook.getActiveWorksheet();
let tmpCell = selectedCell;
const origCell = selectedCell;
const origAddress = origCell.getAddress();
const selectedColor = selectedCell.getFormat().getFill().getColor();
while (selectedCell.getAddress() == origAddress) {
selectedCell = workbook.getSelectedRange();
origCell.getFormat().getFill().setPattern(ExcelScript.FillPattern.grid);
}
while (selectedCell.getAddress() != origAddress) {
selectedCell.getFormat().getFill().setColor(selectedColor);
selectedCell = workbook.getSelectedRange();
}
origCell.getFormat().getFill().setPattern(ExcelScript.FillPattern.solid);
}here is a screen shot after I selected the green cell D4 and then selected the range D6:F10
This is BRILLIANT — Office Scripts FTW!
Thank you for sharing that!
Your script is a clever solution. This is a great practical workaround. The Automate tab and Office Scripts are indeed the modern replacement for VBA macros, especially in Excel Online and cross-platform environments.
I'm not sure if this can work quite that way; however, I took the liberty of taking up your suggestion and refining it a bit further 🙂—in doing so, I took into account both the risk of an infinite loop and the scenario where no color was applied to the original cell. Ultimately, everything is now consolidated into a single code block. Please take a look at it and let me know what you think.
function main(workbook: ExcelScript.Workbook) {
let selectedRange = workbook.getSelectedRange();
let origCell = workbook.getActiveCell();
let origAddress = origCell.getAddress();
let selectedColor = origCell.getFormat().getFill().getColor();
// Default to yellow if no color
if (!selectedColor) {
selectedColor = "#FFFF00";
origCell.getFormat().getFill().setColor(selectedColor);
}
// Mark source cell with grid pattern
origCell.getFormat().getFill().setPattern(ExcelScript.FillPattern.grid);
// Wait for user to move away from source
while (selectedRange.getAddress() === origAddress) {
selectedRange = workbook.getSelectedRange();
}
// Apply color until user returns to source cell
while (selectedRange.getAddress().indexOf(origAddress) === -1) {
selectedRange.getFormat().getFill().setColor(selectedColor);
selectedRange = workbook.getSelectedRange();
}
// Restore original cell: remove grid pattern, reapply color
origCell.getFormat().getFill().setPattern(ExcelScript.FillPattern.none);
origCell.getFormat().getFill().setColor(selectedColor);
}Thanks again for contributing this solution.
- m_tarlerMay 20, 2026Silver Contributor
Hi Niko,
First off, thank you and glad you like my idea. I like how you cleaned up my code with appropriate comments and other improvements like pulling the 'grid' pattern outside the loop and removing some of those unused variables I had used during testing. Some of the other changes I'm not as clear about and genuinely interested in how they improve the code.
For example:
- the default color section - I considered adding a condition for 'no fill' but detecting that seems to be acting very inconsistently so I didn't bother, but if I did I would then assume they are trying to apply 'no fill' to the other cell and therefore add the folllowing IF statement to both the loop and maybe the final restore original cell
IF (noFill) {...getFill().clear()} else {...getFill().setColor(selectedColor)}
but without it, it seems to just treat a 'no fill' cell as a white background (haven't tested darkmode to see if it acts differently there)- I presume your comment about an infinite loop is where you changed the While condition to:
(selectedRange.getAddress().indexOf(origAddress) === -1)
but I'm curious how or why that will act differently- and in general I notice you changed to === instead == which from what I understand is often 'preferred' but my understanding is that === is to make a more stringent exact match and so I specifically chose == to allow less strict matching but in practice in this case I don't think it makes a diffence but would love to understand better.
- my last question of curiosity is w/r to:
origCell.getFormat().getFill().setPattern(ExcelScript.FillPattern.none)
and if or how that is different than setting it to 'solid'and again I thought about making this color painter script also include the pattern but again, thought that was maybe an overkill for what they wanted, but wouldn't be that hard to do.
- NikolinoDEMay 20, 2026Platinum Contributor
Hi—as a VBA user, I was immediately captivated and fascinated by just how well certain tasks can be handled using scripts instead of VBA. Your approach hooked me right away... it was the "aha moment" that inspired me to dive deeper into Office Scripts.
As for your questions: I had no intention of changing this beautiful idea—only of refining it a little, of giving it a bit more luster 😊. Here are my thoughts on the matter—the whys and wherefores.
No Fill Detection
You're right — it's inconsistent. getColor() returns null for both "no fill" AND some weird edge cases. Your if(noFill){clear()}else{setColor()} approach is semantically correct but fragile in practice. My yellow default is the pragmatic call — predictable > pure.
Dark mode: null ≠ white there either, so it's even flakier.
indexOf() — Why …
Check
"A1:A5" == "A1"
"A1:A5".indexOf("A1")
Result
false → never exits
0 → exits cleanly
== demands exact match. indexOf() asks "does this range contain the original cell?" — works for single cells AND ranges. That's the whole difference.
& === vs ==
Here? Zero practical difference — both sides are strings. But === is the TS standard: no type coercion, clearer intent. Your == wasn't "looser" here — it would only matter with mixed types (null == undefined → true, etc.). Habit, not necessity. 😊
none vs solid
Functionally identical — both = solid color. none = "erase any pattern, just use color." solid = "set pattern to solid." none is the true default state, so it's the cleaner reset. Think of it as clearPattern() vs setPattern(solid). Same result, none is more explicit.
Pattern Copy?
Dead simple to add — just grab origFill.getPattern() alongside getColor() and apply both in the loop + restore. Took 3 extra lines. Your instinct was right — not overkill at all.
Here the version that copies both color AND pattern...I hope this is feasible in Office Script :-)
function main(workbook: ExcelScript.Workbook) { let selectedRange = workbook.getSelectedRange(); let origCell = workbook.getActiveCell(); let origAddress = origCell.getAddress(); let origFill = origCell.getFormat().getFill(); let selectedColor = origFill.getColor(); let selectedPattern = origFill.getPattern(); // Default to yellow + solid if no color if (!selectedColor) { selectedColor = "#FFFF00"; selectedPattern = ExcelScript.FillPattern.solid; origFill.setColor(selectedColor); origFill.setPattern(selectedPattern); } // Mark source with grid origFill.setPattern(ExcelScript.FillPattern.grid); // Wait for user to move away while (selectedRange.getAddress() === origAddress) { selectedRange = workbook.getSelectedRange(); } // Paint color + pattern until user returns while (selectedRange.getAddress().indexOf(origAddress) === -1) { let targetFill = selectedRange.getFormat().getFill(); targetFill.setColor(selectedColor); targetFill.setPattern(selectedPattern); // NEW: copy pattern too! selectedRange = workbook.getActiveCell(); } // Restore original: remove grid, reapply color + pattern origFill.setPattern(ExcelScript.FillPattern.none); origFill.setColor(selectedColor); origFill.setPattern(selectedPattern); // NEW: restore pattern too! }That was a fantastic deep dive. Your original script was already 90% complete—it’s just the final 10% of stylistic polishing now; nothing more 😊.