Styling the <Autocomplete/> component in Material UI with React to achieve rounded corners

Google's search bar has always been a favorite of mine, with its rounded corners and generous text padding.

https://i.stack.imgur.com/UbKrr.png

I'm attempting to replicate this aesthetic using Material UI's <Autocomplete/> component in my Next.js project, but I'm facing some challenges. Here is what I have so far:

import React, { useState, useEffect } from 'react';
import TextField from '@mui/material/TextField';
import Stack from '@mui/material/Stack';
import Autocomplete from '@mui/material/Autocomplete';
import { borderRadius, Box } from '@mui/system';
import SearchIcon from '@material-ui/icons/Search';


const LiveSearch = (props) => {

  const [jsonResults, setJsonResults] = useState([]);

  useEffect(() => {
    fetch(`https://jsonplaceholder.typicode.com/users`)
      .then(res => res.json())
      .then(json => setJsonResults(json));
  }, []);

  return (
      <Stack sx={{ width: 400, margin: "auto" }}>
        <Autocomplete
          id="Hello"
          getOptionLabel={(jsonResults) => jsonResults.name}
          options={jsonResults}
          noOptionsText="No results"
          isOptionEqualToValue={(option, value) => {
            option.name === value.name
          }}
          renderOption={(props, jsonResults) => (
            <Box component="li" {...props} key={jsonResults.id}>
              {jsonResults.name} - Ahhh
            </Box>
          )}
          renderInput={(params) => <TextField {...params} label="Search users..." />}
        />
                  

      </Stack>

  )
}

export default LiveSearch;

The code above should work flawlessly – it includes an axios call to populate the autocomplete results as well.

https://i.stack.imgur.com/cHZMS.png

I have been experimenting with different methods to add the <SearchIcon /> icon prefix inside the input field without success. My main goal, however, is to figure out how to apply padding. In the Google example, the autocomplete aligns perfectly with the box, but in my implementation, the border-radius rounds the element separately, causing misalignment with the dropdown.

Being new to Material UI, I am still learning how to customize styles effectively. It seems that the border is defined by an internal element, making it challenging to adjust padding or borders directly. Despite trying to set styles using sx, I have not been able to achieve the desired result.

Answer №1

If you want to customize the appearance of the autocomplete feature, you can check out the autocomplete css classes and modify them in your component or apply them in your theme.

<Autocomplete
    componentsProps={{
      paper: {
        sx: {
          width: 350,
          margin: "auto"
        }
      }
    }}
    id="Hello"
    notched
    getOptionLabel={(jsonResults) => jsonResults.name}
    options={jsonResults}
    noOptionsText="No results"
    isOptionEqualToValue={(option, value) => {
      option.name === value.name;
    }}
    renderOption={(props, jsonResults) => (
      <Box component="li" {...props} key={jsonResults.id}>
        {jsonResults.name} - Ahhh
      </Box>
    )}
    renderInput={(params) => (
      <TextField
        {...params}
        label="Search users..."
        sx={{
          "& .MuiOutlinedInput-root": {
            borderRadius: "50px",

            legend: {
              marginLeft: "30px"
            }
          },
          "& .MuiAutocomplete-inputRoot": {
            paddingLeft: "20px !important",
            borderRadius: "50px"
          },
          "& .MuiInputLabel-outlined": {
            paddingLeft: "20px"
          },
          "& .MuiInputLabel-shrink": {
            marginLeft: "20px",
            paddingLeft: "10px",
            paddingRight: 0,
            background: "white"
          }
        }}
      />
    )}
  />

Try it out: https://codesandbox.io/s/infallible-field-qsstrs?file=/src/Search.js

Answer №2

After some trial and error, I managed to align the edges (problem solved, check out the updates). Here's how I added the Search icon using renderInput and removed the expand and collapse arrows at the end of the bar by setting freeSolo={true} (although this allows user input not bound to provided options).

import { Search } from '@mui/icons-material';
import { Autocomplete, AutocompleteRenderInputParams, InputAdornment } from '@mui/material';

...
<Autocomplete
            freeSolo={true}
            renderInput={(renderInputParams: AutocompleteRenderInputParams) => (
                <div ref={renderInputParams.InputProps.ref}
                    style={{
                        alignItems: 'center',
                        width: '100%',
                        display: 'flex',
                        flexDirection: 'row'
                    }}>
                    <TextField style={{ flex: 1 }} InputProps={{
                        ...renderInputParams.InputProps, startAdornment: (<InputAdornment position='start'> <Search /> </InputAdornment>),
                    }}
                        placeholder='Search'
                        inputProps={{
                            ...renderInputParams.inputProps
                        }}
                        InputLabelProps={{ style: { display: 'none' } }}
                    />
                </div >
            )}
            ...
/>

Let's ignore the colors and styling for now, here's a visual representation:

https://i.stack.imgur.com/umzRx.png

Updates

I achieved edge alignment by adjusting the border-radius with CSS, setting the bottom left and right corners to 0, and the top ones to 20px.

Watch this demo:

https://i.stack.imgur.com/3IC7w.gif

Below are the CSS modifications made. The bottom border was intentionally kept for differentiation between search and results - feel free to customize it as desired. (Note: SCSS was utilized with color variables declared at the beginning).

div.MuiAutocomplete-root div.MuiOutlinedInput-root { /* Search bar when not in focus */
  border-radius: 40px;
  background-color: $dark-color;
}

div.MuiAutocomplete-root div.MuiOutlinedInput-root.Mui-focused { /* Search bar when focused */
  border-radius: 20px 20px 0px 0px !important;
}

div.MuiAutocomplete-root div.Mui-focused fieldset { /* fieldset element is what controls the border color. Leaving only the bottom border when dropdown is visible */
  border-width: 1px !important;
  border-color: transparent transparent $light-gray-color transparent !important;
}

.MuiAutocomplete-listbox { /* To control the background color of the listbox, which is the dropdown */
  background-color: $dark-color;
}

div.MuiAutocomplete-popper div { /* To get rid of the rounding applied by Mui-paper on the dropdown */
  border-top-right-radius: 0px;
  border-top-left-radius: 0px;
}

Answer №3

To create rounded corners in your fieldset, simply apply a border radius:

<Autocomplete
  sx={{ '& fieldset': { borderRadius: 33 }}}
/>

View Example on Codesandbox

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a seamless integration between a multi-step form in React and React Router

I've been learning how to use React + ReactRouter in order to create a multi-step form. After getting the example working from this link: , I encountered an issue. The problem with the example is that it doesn't utilize ReactRouter, causing the ...

The CSS child selector seems to be malfunctioning as it is affecting all descendants of the specified type

Struggling with creating a menu containing nested lists. Attempted using a child selector (#menu-novo li:hover > ul) to display only immediate descendants, but all are still showing. Any suggestions or solutions for this issue? #menu-novo-container { ...

Using Next.js with Firebase emulators

I've been struggling to configure Firebase's V9 emulators with Next.js, but I keep running into the same error message. See it here: https://i.stack.imgur.com/Uhq0A.png The current version of Firebase I'm using is 9.1.1. This is how my Fir ...

Verify the functionality of JavaScript to ensure it is enabled and functioning properly

I have experimented with various methods to determine if JavaScript is enabled and running correctly. Typically, I would use a simple test like this: $('.jstest').html('JavaScript works.'); <p class='jstest'></p> ...

The background image is not displaying correctly

I've been struggling to add a background to the menu section at the top of my webpage. I uploaded the image to www.ra3manifesto.co.nf and want the logo, h1, and menu bar to be placed on top of it. I attempted to set this background using the following ...

How to make Jquery skip over elements with a particular data attribute

I am looking to select all elements that are labeled with the 'tag' class. Once these items have been selected, I would like to remove any items from the list that contain the attribute 'data-tag-cat'. var tags = $('.tag'); c ...

Next.js: Utilizing a shared class instance throughout SSR-rendered pages

Is there a way to access the App Insights (3rd-party library) object across multiple pages in a Next.js app? My objective is to initialize the object once and then utilize its methods on different pages. To verify if the object remains consistent across pa ...

Is it important to minify JavaScript npm packages?

In my journey of creating numerous npm packages, I find myself pondering over the question: "Should JavaScript npm packages be minified?" I have always held the belief that minifying already minified code is not a good practice, which is why I have refrai ...

The process of accessing a file object by using the file path given

Is there a way to retrieve the file object of an image that is stored in my website's folder without using "input type = "file"? The image is already saved on the website. Here is what I have tried so far: var file = new File([""], "../writeto/image. ...

Creating a user-friendly form with validation in a Vue application using Vuetify.js

I am in the process of incorporating a contact form with basic validation on a Vue.js website using an example from Vuetify.js. Being new to this, I'm unsure about how to implement it within a Vue component. My goal is to have simple client-side form ...

Encountering a "map is not a function" error in REACT following the use of the push method

After pushing an element to an array in a function (event), I encountered the following error: handleAddList(s) { this.setState({lists :this.state.lists.push(s)}); console.log(this.state.lists); } The error message says "lists.map is not a function. ...

Three.js - Controlling Visibility of Text in troika-three-text with Clipping Planes

Has anyone successfully clipped troika-three-text for threejs using clipping planes? I'm having trouble getting it to work. import { Text } from 'troika-three-text' const minClippingPlane = new THREE.Plane(new THREE.Vector3(0, -1, 0), 1) c ...

Could someone assist me with understanding how to use the Load function in JQuery?

I have a set of links with the class "ajax" that are meant to fetch content from an element with the id "test" in the file "data.html" located in the same directory. This content should then be inserted into the div with the id "content" on my page: <s ...

What causes the generation of an outdated object when utilizing the let and new keywords to create a new object within a service function?

Hey there, looking for a basic auth authentication service in angular2? Here's the issue I'm facing: When a user logs in for the first time, everything works smoothly. However, if they try to log in with a different account for the second time, ...

What is the standard practice in AJAX for determining a specific state during page loading?

Since I started diving into the world of serious ajax operations, one question has been on my mind. Let me illustrate with an example. Imagine fetching a standard HTML page for a customer from the server. The URL could look like this: /myapp/customer/54 ...

HTML block failing to implement Bootstrap styling

I am struggling to integrate Bootstrap into Drupal. I have used the 'row' class for the contact ID and added col-sm-12 for title and desc, but it is not working as expected. The width of the container seems off. Also, the accordion.js script work ...

Modifying the appearance of the login field shown in the image

How can I align the login and password fields in the same order on my webpage? When I attempt to adjust their positions using CSS margin commands, both fields end up moving. Any suggestions? ...

Implementing Conditional Attribute Addition in Vue.js

When developing in vue, I encountered this scenario: <v-dialog v-model="data_table.dialog"> I have a variable called is_mobile that is observable. My goal is to modify the tag above based on the value of is_mobile. For instance: <v-dialog v-mod ...

The error encountered during parsing the module for Next.js, Webpack, and TypeScript files (.ts, .tsx) was due to an unexpected token

Here is the content of my next.config.mjs file: export default { webpack: (config) => { // Find rules that includes current directory const rulesWithCurrentDir = config.module.rules.filter((rule) => rule.include && rule.include.incl ...

Exploring ways to overlay 2D text onto my Blender-created 3D model

Having created a 3D model with Blender, I am trying to overlay 2D text over the different meshes of the model. While I have successfully changed the colors of the meshes based on their indices using diffuse.color, I am struggling to draw text over my mesh. ...