Skip to content

fix(theme): make shared focus outlines themeable - #4654

Open
cixzhang wants to merge 1 commit into
mainfrom
fix/focus-outline-consistency
Open

fix(theme): make shared focus outlines themeable#4654
cixzhang wants to merge 1 commit into
mainfrom
fix/focus-outline-consistency

Conversation

@cixzhang

@cixzhang cixzhang commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Why

General interactive focus outlines were defined independently across components, which made small geometry/color differences easy to introduce and made product-style replication harder. This gap showed up while evaluating agentcloud and trying to replicate its styling through Astryx themes.

Astryx also has a design split: input/field focus treatments are distinct from general interactive chrome. This PR intentionally targets the general outline only.

Theme API

This PR makes the general focus outline themeable as a virtual component target:

defineTheme({
  name: 'custom',
  components: {
    'focus-outline': {
      base: {
        outlineOffset: '4px',
        ':focus-visible': {
          outline: '2px solid var(--color-accent)',
        },
        ':has(:focus-visible)': {
          outline: '2px solid var(--color-accent)',
        },
      },
    },
  },
});

Rendered general controls receive the shared astryx-focus-outline class through the new internal focusOutlineProps helper, so theme overrides attach to a single shared class instead of each component reconstructing outline CSS independently.

What

  • Adds an internal focus-outline prop helper that applies both:
    • the default StyleX focus outline class, and
    • themeProps('focus-outline') / .astryx-focus-outline.
  • Reuses that helper across general interactive chrome: buttons, links, navigation, cards, list/tree items, tabs, pagination, dialogs, and similar non-form controls.
  • Keeps outline primitive values private inside the helper.
  • Leaves form/input focus treatments out of scope.
  • Documents astryx-focus-outline as a theme target and updates the theme-build registry test so virtual non-TSX targets are discovered.

Why not tokens?

Tokens would cover simple color/width/offset cases, but they do not model richer CSS treatments well: animated outlines, layered rings, or state-specific outline behavior. A virtual component-style target gives theme authors normal CSS override expressiveness without adding new outline tokens.

Open question

If we want a more guided API later, we can still add a top-level focusOutline config that compiles down to this same focus-outline theme target. This PR establishes the shared class target first.

Risk

Low-to-medium. The intended visual output stays the same for default themes, but the focus outline class is now shared and themeable across general controls. Inputs are intentionally unchanged.

Testing

  • git diff --check
  • pnpm -F @astryxdesign/core typecheck
  • pnpm exec vitest run packages/cli/clients/cli/commands/build-theme.registry.test.mjs
  • Commit hook: pnpm check:sync && pnpm check:package-boundaries && pnpm check:changesets && pnpm check:demo-media && pnpm check:executable-bits

@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Error Error Aug 3, 2026 3:08am

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 2, 2026
@github-actions github-actions Bot added the needs:design-review Affects visuals — Design should review label Aug 2, 2026
@cixzhang cixzhang changed the title feat(theme): add shared focus outline tokens fix(theme): consolidate shared focus outlines Aug 2, 2026
@cixzhang
cixzhang force-pushed the fix/focus-outline-consistency branch from ce99cfc to 4c808b1 Compare August 2, 2026 15:29
@cixzhang cixzhang changed the title fix(theme): consolidate shared focus outlines RFC: shared focus outline strategy Aug 2, 2026
@cixzhang
cixzhang force-pushed the fix/focus-outline-consistency branch from 4c808b1 to 1eba42f Compare August 2, 2026 21:29
':active': `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`,
},
outline: {
default: null,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of nice to have which is an error-specific outline color.

@cixzhang
cixzhang force-pushed the fix/focus-outline-consistency branch from 1eba42f to 96b7019 Compare August 3, 2026 03:06
@cixzhang cixzhang changed the title RFC: shared focus outline strategy fix(theme): make shared focus outlines themeable Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. needs:design-review Affects visuals — Design should review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant