> All in One 586

Ads

Tuesday, May 12, 2026

Clear today!



With a high of F and a low of 47F. Currently, it's 60F and Clear outside.

Current wind speeds: 8 from the East

Pollen: 0

Sunrise: May 12, 2026 at 05:41PM

Sunset: May 13, 2026 at 07:55AM

UV index: 0

Humidity: 41%

via https://ift.tt/jsi2ekA

May 13, 2026 at 10:02AM

Soon We Can Finally Banish JavaScript to the ShadowRealm

It’s gonna be tough to keep it together on this one. Okay. I got this. I am a professional technical writer. Straight face; all-business. Ahem: if you’ve been following the ongoing work at TC39 (the standards body responsible for maintaining and developing the standards that inform JavaScript) you may have encountered some of their recent work on ShadowRealmssnrk. Sorry! Sorry, I’m good! Just, whew ­— what a name, “ShadowRealms.” Okay, hang on, let me start at the beginning. Maybe that will help.

It’s exceptionally likely you’ve seen JavaScript described as “single-threaded” at some point — that’s usually pretty high up on the list of JavaScript fundamentals, alongside “case sensitive,” “whitespace insensitive,” and “bad at math.” That is correct, in the strict “computer science” sense, but it still gets my hackles up a little whenever I see it.

I mean, accurate in that JavaScript isn’t multi-threaded, for sure. A script is always executed in a very linear way — top to bottom, left to right, one execution context after another, winding up the call stack and then back down again. It’s just that you eventually come to learn about something like Web Workers, which — not to put too fine a point on this — allow you to execute JavaScript code in another thread. That’s where I think “JavaScript is single-threaded” becomes a less helpful framing, because even though JavaScript isn’t a multi-threaded language, a JavaScript application can make use of multiple threads.

It’s a better framing — and every bit as technically accurate — to say that a JavaScript realm is single-threaded. A realm refers to the environment where code is executed: a browser tab is a realm, and within that realm is the single thread where JavaScript is executed — the main thread. A Web Worker is a realm with a worker thread. JavaScript running in a cross-origin iframe is running in that iframe realm’s main thread. We can’t, for example, offload the execution of a single function to another thread — JavaScript is itself single-threaded, as a language. But a JavaScript application can span multiple realms and make use of multiple execution threads, and each of those realms can communicate with other realms in specific ways.

Each JavaScript realm has its own global environment. In a browser tab, the global object is the Window interface. The same is true in a non-same-origin iframe within that browser tab — the global object is the Window “owned” by that iframe:

<html>
  <head></head>
  <body>
    <iframe id="theIframe"></iframe>
  </body>

  <script>
  ( () => {
    console.log( window.globalThis );
    // Result: Window {}

    console.log( theIframe.contentWindow.globalThis );
    // Result: Window {}
  })();

  </script>
</html>

These aren’t the same global object:

<html>
  <head></head>
  <body>
    <iframe id="theIframe"></iframe>
  </body>

  <script>
  ( () => {
    console.log( window.globalThis === theIframe.contentWindow.globalThis );
    // Result: false
  })();
  </script>
</html>

The outer page and the inner iframe are two separate realms, both single-threaded, each with their own global objects and their own intrinsic objects:

<html>
  <head></head>
  <body>
    <iframe id="theIframe"></iframe>
  </body>

  <script>
    (() => {
      console.log( window.Array );
      /* Result (expanded):
        function Array()
        from: function from()
        fromAsync: function fromAsync()
        isArray: function isArray()
        length: 1
        name: "Array"
        of: function of()
        prototype: Array []
        Symbol(Symbol.species): undefined
        <prototype>: function ()
      */

      console.log( theIframe.contentWindow.Array );
      /* Result (expanded):
        function Array()
        from: function from()
        fromAsync: function fromAsync()
        isArray: function isArray()
        length: 1
        name: "Array"
        of: function of()
        prototype: Array []
        Symbol(Symbol.species): undefined
        <prototype>: function ()
      */

      console.log( window.Array === theIframe.contentWindow.Array );
      // Result: false

    })();
  </script>
</html>

So, as you might expect, any global properties defined in the context of one realm will be unavailable to another:

<html>
  <head></head>
  <body>
    <iframe id="theIframe"></iframe>
  </body>

  <script>
  function globalFunction() {};

  console.log( window.globalFunction );
  // Result: function globalFunction()

  console.log( theIframe.contentWindow.globalFunction );
  // Result: undefined
  </script>
</html>

“Unavailable” — or, depending on how you look at it, unable to interfere with the the global object of another realm. If you’ve been JavaScripting for a while, you know that no matter how meticulous we are about managing scope, the global environment can get pretty messy despite our best efforts. Some of that is on us, sure — a stray variable binding happens to the best of us — but a lot of that clutter is a result of the early design decisions that went into the language itself, like the function declaration in the previous example. When you consider the staggering amount of JavaScript we don’t control that can get piled onto the average project — from frameworks to third-party helper libraries to polyfills to user analytics to advertisements — there’s potential for collisions, to say the least.

Given the global scope pollution that has haunted the language since time immemorial (the 90s), it isn’t hard to imagine the use cases for offloading code to a realm that can act as a sandbox for the execution of JavaScript we don’t want to impact, or be impacted by, whatever is already cluttering up the global scope. We might want to run part of our test suite in a “clean room” where performing the testing can’t potentially interfere with the results of your testing and mock data can’t run afoul of the real thing, or a place to run code we want quarantined away from the realm that contains our JavaScript application itself to prevent third-party libraries that don’t need access to the global environment from cluttering it up, to no benefit.

We can’t do that with realms, as they stand right now — remember, JavaScript is single-threaded in that each realm is single-threaded, and communication between those threads is limited. As undeniable as the use case is, we can’t repurpose an alternate realm to execute code on its single thread of execution, then weave the results of that execution back into the main thread of our primary realm. That’s multi-threaded execution by definition, and not just contrary to the fundamental nature of JavaScript, but, well, let me put it this way: JavaScript allowing multiple threads of execution at the same time mean would problems us new for.

To offload code in this way would require a new kind of realm — one that has its own global and intrinsic objects, but not it’s own thread — a realm where code offloaded to it will still be executed on the main thread of the realm that “owns” that script. A dark reflection of our own realms; a realm the light can never touch, where only fleeting, ephemeral shadows of our banished code can dwell! Imagine a distant peal of thunder, here; maybe also imagine that I’m wearing a cape, maybe I hurl a wine glass to the floor. Y’know, have fun with it. How could you not? I mean, they’re called:

ShadowRealms

The proposed ShadowRealm API introduces a new kind of realm specifically designed for isolation, and only that. A ShadowRealm does not have an execution context of its own — code offloaded to a ShadowRealm will exist in a pseudo-realm with its own global and built-in objects. That code continues to run on the same thread as the code where the ShadowRealm is created; we’re not forced to communicate and share resources back and forth between two separate threads in limited ways. In short, a script is executed the way it would if limited to a single realm, but quarantined away from that outer realm’s intrinsic objects, APIs, global object, and anything our script has done to that global object.

That sounds complicated, but the proposed API would be exceptionally simple in practice:

// Create a ShadowRealm:
const shadow = new ShadowRealm();

function globalFunction() {};

console.log( globalthis.globalFunction );
// Result: function globalFunction()

// Evaluate `globalThis.globalFunction` inside the ShadowRealm:
console.log( shadow.evaluate( 'globalThis.globalFunction' ) );
// Result: undefined

Note: Keep in mind that this code is still theoretical — it doesn’t exist in the ES-262 standard or browsers just yet.

globalFunction is defined on the outer realm’s global object just like we saw earlier, but it isn’t defined on the global object inside of our newly-created ShadowRealm — that ShadowRealm’s global object remains pristine, no matter what we do outside of it. The inverse is true, naturally:

// Create a ShadowRealm:
const shadow = new ShadowRealm();

// Declare a global function inside the ShadowRealm:
shadow.evaluate( 'function globalFunction() {};' );

// It doesn't exist in the outer realm's global object:
console.log( globalthis.globalFunction );
// Result: undefined

// But when we evaluate `globalThis.globalFunction` inside the ShadowRealm:
console.log( shadow.evaluate( 'globalThis.globalFunction' ) );
// Result: function globalFunction()

We’ve declared that function inside the ShadowRealm, and we can call it by way of the variable that references that ShadowRealm object. That function remains quarantined away from the outer global object and that of any other ShadowRealm:

// Create a ShadowRealm:
const firstShadow = new ShadowRealm();
const secondShadow = new ShadowRealm();

// Declare a global function inside the ShadowRealm referenced by `secondShadow`:
secondShadow.evaluate( 'function globalFunction() {};' );

// It doesn't exist in the outer realm's global object:
console.log( globalthis.globalFunction );
// Result: undefined

// It doesn't exist in the global object of the ShadowRealm referencd by `firstShadow`:
console.log( firstShadow.evaluate( 'globalThis.globalFunction' ) );
// Result: undefined

// It only exists within the ShadowRealm referenced by `secondShadow`:
console.log( secondShadow.evaluate( 'globalThis.globalFunction' ) );
// Result: function globalFunction()

“Quarantined” to an extent, that is. ShadowRealms don’t provide a true security boundary in that code running inside a ShadowRealm can still make inferences about code running in other realms. They can be thought of as an integrity boundary, in that code running inside a ShadowRealm can’t directly interfere with another realm — unless we let it, of course. Even though code shunted off into a ShadowRealm can’t interfere with the objects outside of it, we’re still free to use the results of those operations the way we would use the results of that same operation in the host realm:

// Create a ShadowRealm:
const shadow = new ShadowRealm();

// Create a binding that calls a function inside the ShadowRealm:
const shadowFunction = shadow.evaluate( '( value ) => globalThis.someValue = value );

// ...and call our wrapped function using that binding:
shadowFunction( "Hello from the ShadowRealm!" );

// Executing this function in the host realm doesn't _change_ anything here, of course:
console.log( globalThis.someValue );
// Result: undefined

// But we can grab the result from the ShadowRealm:
const shadowValue = shadow.evaluate( 'globalThis.someValue' );

// And use it here in the host realm:
console.log( shadowValue );
// Result: Hello from the ShadowRealm!

Infinite disposable cleanrooms! Pocket dimensions where we can execute whatever code we want, without fear of that code interfering with the scope of any other ShadowRealm or the outer realm — the “light realm,” if you will.

Now, some of you — especially those of you who’ve been doing this since the early days of JavaScript — have probably been recoiling at these examples. You’d be forgiven for thinking that ShadowRealm API is just goth eval, and you wouldn’t be strictly wrong: apart from running in the context of a ShadowRealm, what you’ve seen so far here are basically indirect calls to eval — even subject to the same unsafe-eval Content Security Policy rule.

Fear not for your workflows, however: while these are illustrative examples, this isn’t the only way to put ShadowRealms to use. The proposal includes an importValue method on the ShadowRealm object’s prototype, which allows you to dynamically import modules, then capture and work with exported values and functions:

// spookycode.js
export function greeting() {
 return "Hello from the ShadowRealm!";
}
async function shadowGreeter() {
  // I INVOKE THE DARK POWER OF THE SHADOWREALM- ahem. Sorry.
  const shadow = new ShadowRealm();

  /* 
  * `importValue` returns a promise that resolves with the value of the function 
  * specified in the second argument: 
  */
  const shadowGreet = await shadow.importValue( "./spookycode.js", "greeting" );

  // Call our wrapped function, annnnd...
  shadowGreet();
}

shadowGreeter();
// Result: Hello from the ShadowRealm!

The shadow hasn’t fallen yet

I’m pleased to say that you’ve now seen the entirety of the proposed ShadowRealms API, at this point. The proposal includes only those the two methods you’ve seen here — evaluate and importValue — both means of banishing evaluating code in the context of a ShadowRealm instance while still executing that code in the context of the host realm’s thread.

Again, though: none of this can be put to use just yet. The proposed specification is currently at Stage 2.7 — “approved in principle and undergoing validation,” meaning that it’s only likely to change as a result of feedback from tests and trial implementations in browsers, if at all. You’re playing a move ahead by reading this. When this proposal reaches Stage 3 and we start to see implementations in browsers, you’ll be ready to try it out for yourself. Nay, more than ready — at such time as the awesome power of the ShadowRealm is loosed upon the web, you shall stand at the ready to command its dark and fearsome majjycks! The very realm upon which our code stands shall quake, as— okay, okay, sorry. Look, I can’t help it! I mean, “ShadowRealm,” for cryin’ out loud.


Soon We Can Finally Banish JavaScript to the ShadowRealm originally handwritten and published with love on CSS-Tricks. You should really get the newsletter as well.



from CSS-Tricks https://ift.tt/BKdt0iT
via IFTTT

Monday, May 11, 2026

Clear today!



With a high of F and a low of 53F. Currently, it's 66F and Clear outside.

Current wind speeds: 10 from the South

Pollen: 0

Sunrise: May 11, 2026 at 05:42PM

Sunset: May 12, 2026 at 07:54AM

UV index: 0

Humidity: 34%

via https://ift.tt/HJnNqlh

May 12, 2026 at 10:02AM

Why Keyboard Users Can’t Scroll Your Overflow Containers

So, you build a data table with long rows, lots of columns, and horizontal scroll on the container. It works fine with a mouse and you ship it.

But! When a keyboard user Tabs into the table, its focus lands on a cell. Then they press the arrow keys to read across the row but nothing happens. They try Tab again, but this time it jumps to the next interactive element entirely outside the table. The rest of the content is there and screen reader users can navigate it just fine, but there is no way to scroll the container without a mouse.

You may have never noticed this because you most likely only test with a mouse. Your screen reader users never noticed because they navigate the accessibility tree, not the scroll container. The only person it traps is the sighted keyboard user and most teams never test for that.

I didn’t either, until someone filed a bug I couldn’t reproduce until I put my mouse away.

Tab lands inside the table, but the wrapper was skipped entirely and there is no keyboard handle on the container.

Focus Management and Scroll Containers Are Not the Same Thing

Keyboard focus follows tab order. The tab order then follows interactive elements, like buttons, links, inputs — basically anything the browser considers actionable. That’s the system the spec built for keyboard navigation.

Scroll containers are a completely different system because they are layout primitive. What I mean by that is the browser handles overflowing content in different ways any time you set overflow to auto, scroll, or hidden on an element. The browser’s job is to manage overflowing content, not necessarily navigate it. The spec never classified overflow as interactive.

The gap between those two systems is where keyboard users fall through.

This is not a browser bug. Every major browser behaves identically here because they are all following the same spec and the scroll container and focus management are both doing their jobs, although they were not designed to work together.

The CSS Properties That Create Scroll Containers Without Warning

I briefly mentioned a few overflow property values that affect the way overflow is handled, but which values actually create scroll containers? auto is the obvious one, but the scroll containers have a habit of appearing where you least expect them.

For example, it’s worth remembering that overflow is a shorthand. And it’s a little weird how the constituents work. Like, setting the overflow-x constituent to auto to handle horizontal overflow implicitly sets overflow-y to auto. So, a container you’re managing for horizontal scrolling is also a vertical scroll container, and keyboard users can’t scroll either axis without a mouse.

/* This: */
.table-wrapper {
  overflow-x: auto;
}

/* ...is the equivalent of this: */
.table-wrapper {
  overflow-x: auto;
  overflow-y: auto;
}

The same thing happens with overflow: hidden which most developers use it to clip content or clear floats. It might not be obvious, but hidden still creates a scroll container. The content is clipped, not gone (which could be an accidental form of “data loss”), and keyboard users can still focus into it; they just can’t scroll to any of it.

There are less obvious triggers, too. More properties like transform, filter, perspective, will-change (referencing transform), contain (set to paint), and content-visibility (set to auto) all create scroll containers. You may have added one of these for a performance optimization or an animation and quietly created a keyboard trap at the same time.

/* Added for a smooth animation */
.panel {
  transform: translateZ(0);
  overflow: hidden; /* clipping the content */
}

/* Result: .panel is now a scroll container
    keyboard users can focus into it but can't scroll it */

One of the reasons this bug ships so often is that the scroll container wasn’t intentional and nobody audited it because nobody knew it was there.

The Fix

The “fix” is adding tabindex="0" to the scroll container in the markup:

<div class="scroll-container" tabindex="0">
  <!-- scrollable content -->
</div>

That puts the container in the tab order so keyboard users can now Tab to it. And once it has focus, the arrow keys scroll it. The browser handles the rest.

But that is only part of the fix. Adding tabindex without an accessible name means a screen reader encounters a focusable element with nothing to announce. A plain div with tabindex="0" has no name, and the screen reader says nothing useful. You need to add an aria-label that describes what the container holds.

​​role="region"​ and aria-label​ work together. The role tells assistive technology this is a landmark region. The label is what gets announced when focus lands on it. Without the label, screen readers announce”region” and nothing else. That tells the user nothing about what they’re about to scroll through.1

<!-- This is too vague -->
<div
  class="scroll-container"
  tabindex="0"
  aria-label="scrollable"
  role="region"
>
  <!-- scrollable content -->
</div>

<!-- This is more descriptive -->
<div
  class="scroll-container"
  tabindex="0"
  aria-label="Monthly sales data, scrollable"
  role="region"
>
  <!-- scrollable content -->
</div>

Another common problem when working with scroll containers that need to support keyboard tabbing is using visible and obvious focus styling. It’s common to see outline: none or outline: 0 as a design requirement. But then the container is selectable, but invisible. Keyboard users will land on it with no clear indication. Focus styles are indeed style-able, so we can still make then obvious and attractive if the design calls for something custom:

.scroll-container:focus-visible {
  outline: 2px solid #005fcc;
  outline-offset: 2px;
}

The outline color doesn’t need to match your brand exactly, It just needs a two-color combination to ensure contrast with all components, per WCAG’s techniques:

When tabindex="0" Isn’t the Answer

Making a scroll container focusable isn’t always the right call.

If you can’t write a clear and useful aria-label for the container, that’s a signal the content might need restructuring rather than an interactive patch. A scroll container that wraps a single image, a decorative element, or content that’s already fully reachable by tab order doesn’t need to be in the tab order itself. Putting it there adds noise without adding value.

​​That said, if a container holds a large number of focusable items, fifty links in a sidebar or a long list of cards, a single Tab stop on the wrapper may actually be preferable to forcing keyboard users through every item individually. The trade-off shifts when the list is long enough that tabbing through it becomes its own burden. In those cases, tabindex="0"​ on the container is the right call even if the items inside are already focusable.

The harder call is when every item inside already has independent keyboard interaction, e.g., a list of buttons, set of links, or a group of form fields. All of these are already in the tab order so users can reach each one with Tab. If the container is just a visual wrapper around already-accessible content, making the wrapper focusable means users have to Tab through one extra stop to get to the things they actually want to interact with.

The test I run is a simple one. Something like can a keyboard user reach every piece of meaningful content inside the container without tabindex="0" on the wrapper? If yes, skip it. If no, add it.

When the right answer is skipping tabindex, restructuring the DOM is usually the better path. Breaking up long content, splitting it across sections, or using a disclosure pattern with progressive reveal often solves the problem at the layout level without creating accessibility compromise.

How to Audit This

The keyboard-only walkthrough is the fastest test. Unplug or disable your mouse, open the page, and press Tab through every interactive element and every scrollable container. If you reach a container with overflow content and can’t scroll it with the arrow keys after tabbing to it, it needs fixing. On most pages, this would only take about five minutes and the bugs are usually obvious the moment you stop using a mouse.

Note: ​​One thing worth being clear about is that this article is desktop-focused. Virtual keyboards on iOS and Android interact with scroll containers differently, and touch navigation has its own set of considerations. If mobile keyboard accessibility is a concern for your project, that warrants its own investigation.

Chrome’s accessibility panel gives you a structural view. Open DevTools, go to the “Accessibility” tab, and inspect a scroll container. If it shows no role and no accessible name, it’s invisible to assistive technology as a navigable element. That’s a quick way to confirm whether a container needs tabindex="0" and aria-label before you touch the code.

Tools like Deque’s Axe-core and WAVE can automatically catch some of these issues. For Axe-core specification you can use the scrollable-region-focusable rule to flag scroll containers that have focusable content but are not themselves focusable. Running axe-core in your CI pipeline means this class of bug gets caught before it reaches production rather than after a user files a ticket.

// axe-core in a Jest test
import axe from 'axe-core';

test('scroll containers are keyboard accessible', async () => {
  const results = await axe.run(document.body, {
    rules: { 'scrollable-region-focusable': { enabled: true } }
  });
  expect(results.violations).toHaveLength(0);
});

One thing axe-core misses is containers that have overflow content but no focusable children. Those won’t trigger the rule because there’s nothing to Tab into. The keyboard walkthrough catches these cases but the automated tool does not.

How I Approach This Now

Here are the three questions I ask myself:

  1. Does the scroll container hold content that can’t otherwise be reached by keyboard**?** That’s stuff like a data table, a code block, a chat log or a custom carousel — basically anything where the only way to see all the content is to scroll. If the answer is yes, add tabindex="0", an aria-label, and a visible :focus-visible style. All three together. Not just the attribute.
  2. Can every piece of meaningful content inside be reached by **Tab** without scrolling? If the container wraps a list of links or a group of buttons, the content is already keyboard-accessible. That is, unless there’s visually hidden content due to overflow. If the container has overflow content that’s not visually visible but is in tab order, users still need a way to scroll to see it. Making the wrapper focusable adds tab stops without adding access. Skip it.
  3. Is the container the result of an unintentional overflow trigger from transform, contain, or similar? If you added a property for reasons unrelated to scrolling and it created a scroll container as a side effect, consider removing the property if you can, or add tabindex="0" only if there’s content that genuinely needs it.

That’s the whole decision tree. The fix is simple once you know the container exists, but the hard part is knowing it’s there. That’s what the keyboard walkthrough is for.

The Test That Changes How You Build

The keyboard walkthrough takes no more than five minutes but most developers never run it because they assume their users use a mouse. Most of them are correct, most of the time. But the sighted keyboard user is real, and they’re using your product right now, and they’ve quietly learned which interfaces to avoid because they’re not worth the frustration.

Using tabindex="0" won’t fix everything. It won’t fix a poorly structured DOM, a missing accessible name, or a focus style that was stripped out in a global CSS reset. But it closes the gap between what looks accessible and what actually is, and it costs almost nothing to add.

The thing I keep coming back to is that this bug is invisible to the developer, invisible to the screen reader user, and invisible to automated testing until you configure it specifically to look. The only way to find it is to use the product the way the affected user does, which is the test so put your mouse away.

Further Reading


Why Keyboard Users Can’t Scroll Your Overflow Containers originally handwritten and published with love on CSS-Tricks. You should really get the newsletter as well.



from CSS-Tricks https://ift.tt/q0fsMnV
via IFTTT

Sunday, May 10, 2026

Mostly Clear today!



With a high of F and a low of 44F. Currently, it's 53F and Clear outside.

Current wind speeds: 11 from the South

Pollen: 0

Sunrise: May 10, 2026 at 05:42PM

Sunset: May 11, 2026 at 07:53AM

UV index: 0

Humidity: 70%

via https://ift.tt/2FYs6w7

May 11, 2026 at 10:02AM

Saturday, May 9, 2026

Showers today!



With a high of F and a low of 42F. Currently, it's 56F and Mostly Cloudy/Wind outside.

Current wind speeds: 20 from the North

Pollen: 0

Sunrise: May 9, 2026 at 05:44PM

Sunset: May 10, 2026 at 07:52AM

UV index: 0

Humidity: 56%

via https://ift.tt/4YqxDXz

May 10, 2026 at 10:02AM

Friday, May 8, 2026

Mostly Clear today!



With a high of F and a low of 47F. Currently, it's 53F and Clear outside.

Current wind speeds: 4 from the Southeast

Pollen: 0

Sunrise: May 8, 2026 at 05:45PM

Sunset: May 9, 2026 at 07:51AM

UV index: 0

Humidity: 51%

via https://ift.tt/3OCtbMq

May 9, 2026 at 10:02AM

Clear today!

With a high of F and a low of 47F. Currently, it's 60F and Clear outside. Current wind speeds: 8 from the East Pollen: 0 Sunrise...