Stamping a watermark across an APEX page

Oracle APEX / Technique

Stamping a watermark across an APEX page

There is no checkbox for this in APEX, and that is exactly why it makes a fun little build. Here is how I put a CONFIDENTIAL watermark over a report with nothing but a few lines of CSS.

I had a page full of customer data the other day and I wanted it to visibly read CONFIDENTIAL without bolting on a plugin or touching the data. My first instinct was to go looking for a watermark attribute somewhere in Page Designer. Watermark in APEX is not a feature you switch on, it is a small pattern you assemble, and once you see how the pieces fit it takes about five minutes.

So I went down the rabbit hole, and this post is the clean version of what I landed on: a simple overlay, the one gotcha that will trip you up, and a couple of ways to take it further. Here is the end result we are working toward.

Preview / the finished effect
Employees Interactive Report
EmpnoEnameJobSal
7839KINGPRESIDENT5000
7698BLAKEMANAGER2850
7566JONESMANAGER2975
7788SCOTTANALYST3000
CONFIDENTIAL
01What it means

First, what do you actually mean by watermark

This word gets used for a few different things in APEX, and picking your version up front saves a lot of confusion. Here is how I think about it.

FlavourWhat it looks likeHow you build it
Page or report overlayBig diagonal CONFIDENTIAL or DRAFT across the contentPure CSS
Dynamic, leak deterrentTiled text showing the logged in user and timeCSS plus &APP_USER.
Item watermarkHint text sitting inside an input fieldThe declarative Placeholder attribute
PDF watermarkA stamp on generated PDF outputA document API or PL/SQL

This post is about the first one, the page overlay, because it is the most visual and the most reusable. I will point at the dynamic version near the end since it is genuinely useful for sensitive screens.

02The simple overlay

Building the simple overlay

The whole idea is to drop a single piece of text on top of your region, rotate it, fade it down to a ghost, and let it sit there. We use a CSS pseudo element so we do not have to add any markup of our own. Here is the build on a plain Interactive Report.

  1. Create a page, choose Report, then Interactive Report.
  2. Set the source SQL to select empno, ename, job, mgr, hiredate, sal, comm, deptno from emp.
  3. In Page Designer select the report region, open Advanced, and set its Static ID to emp_report.
  4. Select the Page node, find the CSS section, and paste the snippet below into Inline.
  5. Run the page. You now have a ghosted CONFIDENTIAL sitting over your data.
CSS
#emp_report {
  position: relative;
}

#emp_report::before {
  content: "CONFIDENTIAL";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 6rem;
  font-weight: 700;
  letter-spacing: .4rem;
  color: rgba(31, 58, 92, .12);
  transform: rotate(-25deg);
  pointer-events: none;
  z-index: 5;
  white-space: nowrap;
  user-select: none;
}

The position: relative on the region is what anchors the overlay, and inset: 0 stretches the pseudo element to cover it completely. Everything else is just styling: the rotation, the faded ink, the spacing. Change the colour and the text and you have a DRAFT or an INTERNAL ONLY stamp in seconds.

03The key line

The one line that matters most

If you copy nothing else from this post, copy this idea. The first time I tried it I left out one property and the report broke in a way that was confusing for a good ten minutes.

Note pointer-events: none is not decorative. Without it the overlay is a giant invisible sheet sitting on top of your report, swallowing every click. Sorting stops working and row links stop working. That one line lets every click pass straight through the watermark to the report underneath.

So the rule of thumb is simple. Any time you float something over interactive content, make it click through. Your users will never know the overlay is there, which is the whole point.

04The tiled version

A tiled version for that real watermark feel

One big word in the middle is great for a stamp. But if you want the proper repeating watermark look, the kind that covers the entire surface, you want a tiny inline SVG tiled across the region. The important part: put it on the overlay, not as a plain background. If you set it as a normal background image it sits behind the report, and the white rows cover it so you only see a thin strip at the top. Keeping it on the ::before overlay puts the pattern on top of the rows where it belongs.

CSS
#emp_report {
  position: relative;
}

#emp_report::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='300' height='180'><text x='10' y='100' fill='rgba(0,0,0,0.08)' font-size='26' font-family='sans-serif' transform='rotate(-25 150 90)'>CONFIDENTIAL</text></svg>");
  background-repeat: repeat;
}

It looks intimidating but it is just an SVG with one line of text, encoded straight into the CSS so there is no file to upload anywhere. Tweak the width and height to change how tightly the pattern tiles, and the fill value to make it lighter or darker.

05Going dynamic

Levelling up: a dynamic watermark

Here is where it gets interesting for sensitive screens. A static CONFIDENTIAL is a label. A watermark that shows the actual logged in user and the current time is a deterrent, because anyone who screenshots the page is now screenshotting their own name.

The catch is that CSS content cannot read a live value, so the pure CSS trick from earlier will not stretch this far. Instead you render the text in a small Static Content region using APEX substitutions, then style that region as the tiled overlay. The markup is as plain as this.

HTML
<div class="leak-mark">&APP_USER. &nbsp; &P1_NOW.</div>

Set P1_NOW from a computation so it carries a timestamp, repeat the text across the region with the same tiling approach, keep it faded and click through, and you have a watermark that quietly says exactly who was looking and when. That is a small thing that makes people think twice.

06Lessons learned

A few things I picked up along the way

  • Always set pointer-events: none on the overlay, or you will lose every interaction underneath it.
  • Keep the colour very faint, somewhere around eight to twelve percent opacity, so data stays readable.
  • Anchor with position: relative on the region and inset: 0 on the overlay so it scales with the region.
  • Use a Static ID rather than a generated one so your CSS selector does not break on the next deploy.
  • For a whole app, move the rule into the Theme Roller custom CSS or a static CSS file instead of repeating it page by page.
  • Test it on a tablet and a phone, since a rotated word that looks great on desktop can spill off a narrow screen.

See it running

The whole thing is a handful of CSS lines over a classic report. Have a look, then go stamp something of your own.

View the live demo

Comments

Popular posts from this blog

Dynamic Triggered Action in Cards

List Link Attributes and Menu Buttons

Gemini , Mistral free AI Editoral in Apex 26.1