Repository: mui/material-ui (TypeScript)
Date: 2021-05-07 15:08:15+00:00
Task type: Bug Fix

Issue:
[Autocomplete] can't change option highlight color
- [x] The issue is present in the latest release.
- [x] I have searched the [issues](https://github.com/mui-org/material-ui/issues) of this repository and believe that this is not a duplicate.

## Current Behavior 😯
The Autocomplete component uses a very light default option highlight and doesn't exposes any CSS props to easily change it as far as i can tell.

## Expected Behavior 🤔
an easy css classname/selector exposed to change the highlight color of the options

currently, it's setting `.MuiAutocomplete-option[data-focus="true"]` but I can't figure out how to actually change that using makeStyles or any other documented way


Issue discussion:
@jdoklovic Thanks for opening this issue. This raises interesting underlying concerns. I see a couple of dimensions to it.

1. **attribute**. I'm not aware of any cases, across all our components, where we use `data-` attributes to solve this problem. Maybe I was too influenced when benchmarking Reach UI. So, in this case, I would propose that we stick to the patter we use elsewhere: `.Mui-disabled` and `.Mui-selected` class names. This would be a breaking change.
2. **UI**. This lab component is a great opportunity to continue the experiment on https://github.com/mui-org/material-ui/issues/10870#issuecomment-575609444. The last iteration was on #19612.

---

Regarding your very issue, there is nothing specific, pick whatever styling solution you use in your app, use the correct CSS selector, make sure you have more CSS specificity, you are good.
@oliviertassinari Thanks for the info. By chance do you know what I could put in makeStyles from MUI to target the attribute selector?  I haven't had any luck doing it and I currently don't have any stylesheets and want to avoid adding one just for this.

I should also note that this is going to be used in a themeable host where we use a "dynamic" MUI theme that adjusts it's colors and typography based on the host theme, so it would be nice to be able to target this selector in a theme.

Thanks again!
just for clarity, I've tried hacking it using this code:

```
const useStyles = makeStyles({
    'option[data-focus="true"]': {
        background: 'blue'
    }
}, { name: 'MuiAutocomplete' });
```
I can see that it does indeed generate the proper classname, however, the component complains that it doesn't accept the key:

![image](https://user-images.githubusercontent.com/620106/74544657-1e50c380-4f0d-11ea-8508-930149a7ebb6.png)

Actually, I found a solution that will work for now.
I just needed to do:

```jsx
const useStyles = makeStyles({
    '@global': {
        '.MuiAutocomplete-option[data-focus="true"]': {
            background: 'blue'
        }
    }

});
```
and then in my component function, simply call
`useStyles();`

It's not great, but it will get me through until a "real" solution is found.

Thanks!
@jdoklovic This is, from my perspective a "support request"

> I should also note that this is going to be used in a themeable host where we use a "dynamic" MUI theme that adjusts it's colors and typography based on the host theme, so it would be nice to be able to target this selector in a theme.

You could use the theme directly, but global styles (like you did) works great too!

```jsx
createMuiTheme({
  overrides: {
    MuiAutocomplete: {
      option: {
        '&[data-focus="true"]': {
          backgroundColor: 'red',
        },
      },
    },
  },
})
```
Regarding the normalization of the API, I have the following diff in mind:

```diff
diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
index 463ff0f2f..b6405c638 100644
--- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
+++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
@@ -204,7 +204,7 @@ export const styles = theme => ({
     '&[aria-selected="true"]': {
       backgroundColor: theme.palette.action.selected,
     },
-    '&[data-focus="true"]': {
+    '&.Mui-focused': {
       backgroundColor: theme.palette.action.hover,
     },
     '&:active': {
diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.test.js b/packages/material-ui-lab/src/Autocomplete/Autocomplete.test.js
index bf6f017c9..482f4dace 100644
--- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.test.js
+++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.test.js
@@ -67,7 +67,7 @@ describe('<Autocomplete />', () => {
       );

       function checkHighlightIs(expected) {
-        expect(getByRole('listbox').querySelector('li[data-focus]')).to.have.text(expected);
+        expect(getByRole('listbox').querySelector('li.Mui-focused')).to.have.text(expected);
       }

       checkHighlightIs('one');
@@ -782,7 +782,7 @@ describe('<Autocomplete />', () => {
       fireEvent.keyDown(document.activeElement, { key: 'ArrowDown' }); // goes to 'two'

       function checkHighlightIs(expected) {
-        expect(listbox.querySelector('li[data-focus]')).to.have.text(expected);
+        expect(listbox.querySelector('li.Mui-focused')).to.have.text(expected);
       }

       checkHighlightIs('two');
diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
index 3c01bb4b3..edf689f65 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
@@ -146,9 +146,9 @@ export default function useAutocomplete(props) {
       return;
     }

-    const prev = listboxRef.current.querySelector('[data-focus]');
+    const prev = listboxRef.current.querySelector('.Mui-focused');
     if (prev) {
-      prev.removeAttribute('data-focus');
+      prev.classList.remove('Mui-focused');
     }

     const listboxNode = listboxRef.current.parentElement.querySelector('[role="listbox"]');
@@ -169,7 +169,7 @@ export default function useAutocomplete(props) {
       return;
     }

-    option.setAttribute('data-focus', 'true');
+    option.classList.add('Mui-focused');

     // Scroll active descendant into view.
     // Logic copied from https://www.w3.org/TR/wai-aria-practices/examples/listbox/js/listbox.js
```
```
createMuiTheme({
  overrides: {
    MuiAutocomplete: {
      option: {
        '&[data-focus="true"]': {
          backgroundColor: 'red',
        },
      },
    },
  },
})
```
FYI
typescript is complaining because all MUIAutoComplete classes are not in ThemeOptions object.
@jeromeSH26 See #19655.
@oliviertassinari merci Olivier, but I already had a look at the official answer ;-)
Of course extending the default theme is a solution (that I have partialy applied BTW) but this is not very dry and quite annoying as you mostly need to recreate/reimporte all the types related to the classes already done by the lab. ;-)

Would you mind having a look at #19827  ? This is also an annoying situation I'm facing and can't fixed.

Rgds


@oliviertassinari there is another problem with hover color. 
When you select items by keyboard, the hover state in Select is palette.action.selected, but for Autocomplete is palette.action.hover. 

Could we bring them to one view? 
@rash2x We need to revamp the state styles, see #5186.
I'm able to change it by doing:

```js
createStyles({
    listbox: {
      padding: 0,
    },
    option: {
      borderBottom: `1px solid ${theme.palette.system[5]}`,
      // Hover
      '&[data-focus="true"]': {
        backgroundColor: theme.palette.secondSurface.light,
        borderColor: 'transparent',
      },
      // Selected
      '&[aria-selected="true"]': {
        backgroundColor: theme.palette.secondSurface.main,
        borderColor: 'transparent',
      },
    },
  });

<Autocomplete
   classes={{
      option: cs.option,
      listbox: cs.listbox,
   }}
/>
```


@matthlavacka  Thank you,i can change any props with this
To fix the TypeScript error I added the MuiAutocomplete with AutocompleteClassKey to the ComponentNameToClassKey which is used in the Overrides Interface to declare the keys and properties.

```
import { AutocompleteClassKey } from '@material-ui/lab/Autocomplete';

declare module '@material-ui/core/styles/overrides' {
  interface ComponentNameToClassKey {
    MuiAutocomplete: AutocompleteClassKey
  }
}
```
@wald-tq See https://next.material-ui.com/components/about-the-lab/#typescript or a simpler solution.
@oliviertassinari thanks a lot!
I also found also this in the changelog: https://github.com/mui-org/material-ui/blob/next/CHANGELOG.md#4102
Guess we are updating from 4.9.11 to 4.10.2

After updating the packages and trying to use the described method:

```
import type '@material-ui/lab/themeAugmentation';
```

I figured out, that it won't compile when using the latest react-scripts@3.4.3.
See: https://stackoverflow.com/a/60464514/605586

I hope that we get a update soon.

Solution patch:
diff --git a/docs/src/pages/guides/migration-v4/migration-v4.md b/docs/src/pages/guides/migration-v4/migration-v4.md
--- a/docs/src/pages/guides/migration-v4/migration-v4.md
+++ b/docs/src/pages/guides/migration-v4/migration-v4.md
@@ -411,6 +411,13 @@ As the core components use emotion as a styled engine, the props used by emotion
   2. `select-option` to `selectOption`
   3. `remove-option` to `removeOption`
 
+- Change the CSS rules that use `[data-focus="true"]` to use `.Mui-focused`. The `data-focus` attribute is not set on the focused option anymore, instead, global class names are used.
+
+  ```diff
+  -'.MuiAutocomplete-option[data-focus="true"]': {
+  +'.MuiAutocomplete-option.Mui-focused': {
+  ```
+
 ### Avatar
 
 - Rename `circle` to `circular` for consistency. The possible values should be adjectives, not nouns:
diff --git a/packages/material-ui/src/Autocomplete/Autocomplete.js b/packages/material-ui/src/Autocomplete/Autocomplete.js
--- a/packages/material-ui/src/Autocomplete/Autocomplete.js
+++ b/packages/material-ui/src/Autocomplete/Autocomplete.js
@@ -338,7 +338,7 @@ const AutocompleteListbox = experimentalStyled(
     [theme.breakpoints.up('sm')]: {
       minHeight: 'auto',
     },
-    '&[data-focus="true"]': {
+    [`&.${autocompleteClasses.focused}`]: {
       backgroundColor: theme.palette.action.hover,
       // Reset on touch devices, it doesn't add specificity
       '@media (hover: none)': {
@@ -354,7 +354,7 @@ const AutocompleteListbox = experimentalStyled(
     },
     '&[aria-selected="true"]': {
       backgroundColor: alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity),
-      '&[data-focus="true"]': {
+      [`&.${autocompleteClasses.focused}`]: {
         backgroundColor: alpha(
           theme.palette.primary.main,
           theme.palette.action.selectedOpacity + theme.palette.action.hoverOpacity,
diff --git a/packages/material-ui/src/useAutocomplete/useAutocomplete.js b/packages/material-ui/src/useAutocomplete/useAutocomplete.js
--- a/packages/material-ui/src/useAutocomplete/useAutocomplete.js
+++ b/packages/material-ui/src/useAutocomplete/useAutocomplete.js
@@ -296,9 +296,9 @@ export default function useAutocomplete(props) {
       return;
     }
 
-    const prev = listboxRef.current.querySelector('[data-focus]');
+    const prev = listboxRef.current.querySelector('[role="option"].Mui-focused');
     if (prev) {
-      prev.removeAttribute('data-focus');
+      prev.classList.remove('Mui-focused');
       prev.classList.remove('Mui-focusVisible');
     }
 
@@ -320,7 +320,7 @@ export default function useAutocomplete(props) {
       return;
     }
 
-    option.setAttribute('data-focus', 'true');
+    option.classList.add('Mui-focused');
     if (reason === 'keyboard') {
       option.classList.add('Mui-focusVisible');
     }


Test patch:
diff --git a/packages/material-ui/src/Autocomplete/Autocomplete.test.js b/packages/material-ui/src/Autocomplete/Autocomplete.test.js
--- a/packages/material-ui/src/Autocomplete/Autocomplete.test.js
+++ b/packages/material-ui/src/Autocomplete/Autocomplete.test.js
@@ -19,7 +19,7 @@ import Autocomplete, {
 } from '@material-ui/core/Autocomplete';
 
 function checkHighlightIs(listbox, expected) {
-  const focused = listbox.querySelector('[role="option"][data-focus]');
+  const focused = listbox.querySelector(`.${classes.focused}`);
 
   if (expected) {
     if (focused) {