Files
supabase/apps/studio/components
Saxon FletcherandDanny White 692b14d47b fix(ui): opaque sticky table column hover (#47668)
## Problem

On tables with a sticky last column (Database Extensions, OAuth Apps,
Custom Auth Providers), hovering a row lets scrolled cell content show
through the sticky column.

Root cause: row hover uses `bg-surface-200`, which maps to `--muted`
(alpha). That works for normal cells (nothing behind them) but sticky
cells sit above horizontally scrolled content, so the tint is
see-through.

## Solution

In `ShadowScrollArea` when `stickyLastColumn` is set:

- Keep an opaque `bg-surface-100` base on sticky cells
- Composite the muted hover tint via `background-image` so hover matches
`TableRow` without becoming transparent

Also:

- Extensions: use `Table containerProps={{ stickyLastColumn: true }}`
instead of nesting a second `ShadowScrollArea` (same pattern as OAuth /
Custom Auth)
- OAuth Apps and Custom Auth Providers: drop redundant per-cell
`bg-surface-100` / `hover:bg-surface-200` so sticky hover comes only
from `ShadowScrollArea`

| Before | After |
| --- | --- |
| <img width="1042" height="98" alt="27097"
src="https://github.com/user-attachments/assets/204a7dc4-d5ac-40b7-87fb-fdb03982eaad"
/> | <img width="1084" height="101" alt="94456"
src="https://github.com/user-attachments/assets/c6db3607-6bbe-4488-a0a5-81f5a0436d66"
/> |

## Review instructions

1. Open Database Extensions. Narrow the viewport or scroll the table
horizontally so the Enabled column is sticky.
2. Hover a row while Links or description content sits under the Enabled
column. The sticky cell should stay opaque and match the row hover tint
(light and dark).
3. Optionally repeat on Auth → OAuth Apps and Auth → Custom Providers
(actions column).

Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>
2026-10-09 17:12:47 +11:00
..

Writing components

Where to create your components

  • For components that declare the general structure and layout of a page:
    • /components/layouts/xxx
  • For components that are tightly coupled to a specific interface:
    • /components/interfaces/xxx
  • For components that are meant to be reusable across multiple pages:
    • /components/ui/xxx
  • Note: We're gradually moving files out of the to-be-cleaned folder into the respective folders as we refactor

Component structure

  • If a component has constants and utility methods that are tightly coupled to itself, keep them close to the component and enclose them in a folder with an index.tsx as an entry point
  • Otherwise it can just be a file on its own
  • For example:
    • components/ui
      - SampleComponentA
        - SampleComponentA.tsx
        - SampleComponentA.constants.ts
        - SampleComponentA.utils.ts
        - SampleComponentA.types.ts
        - index.ts
      - SampleComponentB.tsx
      

Template for building components


// Declare the prop types of your component
interface ComponentAProps {
  sampleProp: string
}

// Name your component accordingly — use a named export, not a default export
export const ComponentA = ({ sampleProp }: ComponentAProps) => {
  return <div>ComponentA: {sampleProp}</div>
}