[css] Is it possible to center text in select box?

I tried this: http://jsfiddle.net/ilyaD/KGcC3/

HTML:

<select name="state" class="ddList">
    <option value="">(please select a state)</option>
    <option class="lt" value="--">none</option>
    <option class="lt" value="AL">Alabama</option>
    <option class="lt" value="AK">Alaska</option>
    <option class="lt" value="AZ">Arizona</option>
    <option class="lt" value="AR">Arkansas</option>
    <option class="lt" value="CA">California</option>
    <option class="lt" value="CO">Colorado</option>
</select>

CSS:

select { width: 400px; text-align: center; }
select .lt { text-align: center; }

As you can see, it doesn't work. Is there a CSS-only way to center text in the select-box?

This question is related to css

The answer is


You have to put the CSS rule into the select class.

Use CSS text-indent

Example

<select class="day"> /* option 1 option 2 option 3 option 4 option 5 here */ </select>

CSS code

select { text-indent: 5px; }

I have always gotten away with the following hack to get it to work with css only.

padding-left: 45%;
font-size: 50px;

padding will center the text and can be tweaked for the text size :)

This is obviously not 100% correct from a validation point of view I guess but it does the job :)


While you cannot center the option text within a select, you can lay an absolutely positioned div over the top of the select to the same effect:

#centered
{
  position: absolute;
  top: 10px;
  left: 10px;
  width: 818px;
  height: 37px;
  text-align: center;
  font: bold 24pt calibri;
  background-color: white;
  z-index: 100;
}

#selectToCenter
{
  position: absolute;
  top: 10px;
  left: 10px;
  width: 840px;
  height: 40px;
  font: bold 24pt calibri;
}

$('#selectToCenter').on('change', function () {
    $('#centered').text($(this).find('option:selected').text());
});

<select id="selectToCenter"></select>
<div id="centered"></div>

Make sure the both the div and select have fixed positions in the document.


It's not 100% yet, but you can use this snippet!

text-align-last: center; // For Chrome text-align: center; // For Firefox

Doesn't work on Safari or Edge, for now!


That's for align right. Try it:

select{
    text-align-last:right;
    padding-right: 29px;
    direction: rtl;
}

the browser support for the text-align-last attribute can be found here: https://www.w3schools.com/cssref/css3_pr_text-align-last.asp It looks like only Safari is still not supporting it.


try this :

select {
    padding-left: 50% !important;
    width: 100%;
}

Alternative "fake" solution if you have a list with options similar in text length (page select for example):

padding-left: calc(50% - 1em);

This works in Chrome, Firefox and Edge. The trick is here to push the text from the left to the center, then substract the half of length in px, em or whatever of the option text.

enter image description here

Best solution IMO (in 2017) is still replacing the select via JS and build your own fake select-box with divs or whatever and bind click events on it for cross-browser support.


This JS function should work for you

function getTextWidth(txt) {
  var $elm = $('<span class="tempforSize">'+txt+'</span>').prependTo("body");
  var elmWidth = $elm.width();
  $elm.remove();
  return elmWidth;
}
function centerSelect($elm) {
    var optionWidth = getTextWidth($elm.children(":selected").html())
    var emptySpace =   $elm.width()- optionWidth;
    $elm.css("text-indent", (emptySpace/2) - 10);// -10 for some browers to remove the right toggle control width
}
// on start 
$('.centerSelect').each(function(){
  centerSelect($(this));
});
// on change
$('.centerSelect').on('change', function(){
  centerSelect($(this));
});

Full Codepen here: http://codepen.io/anon/pen/NxyovL


If you didn't find any solution, you can use this trick on angularjs or using js to map selected value with a text on the div, this solution is full css compliant on angular but need a mapping between select and div:

_x000D_
_x000D_
var myApp = angular.module('myApp', []);_x000D_
_x000D_
myApp.controller('selectCtrl', ['$scope',_x000D_
  function($scope) {_x000D_
    $scope.value = '';_x000D_
_x000D_
_x000D_
  }_x000D_
]);
_x000D_
.ghostSelect {_x000D_
  opacity: 0.1;_x000D_
  /* Should be 0 to avoid the select visibility but not visibility:hidden*/_x000D_
  display: block;_x000D_
  width: 200px;_x000D_
  position: absolute;_x000D_
}_x000D_
.select {_x000D_
  border: 1px solid black;_x000D_
  height: 20px;_x000D_
  width: 200px;_x000D_
  text-align: center;_x000D_
  border-radius: 5px;_x000D_
  display: block;_x000D_
}
_x000D_
<!doctype html>_x000D_
<html lang="en">_x000D_
_x000D_
<head>_x000D_
  <meta charset="UTF-8">_x000D_
  <title>Example - example-guide-concepts-1-production</title>_x000D_
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>_x000D_
</head>_x000D_
<body ng-app="myApp">_x000D_
  <div ng-app ng-controller="selectCtrl">_x000D_
    <div class=select>_x000D_
      <select ng-model="value" class="ghostSelect">_x000D_
        <option value="Option 1">Option 1</option>_x000D_
        <option value="Option 2">Option 2</option>_x000D_
        <option value="Option 3">Option 3</option>_x000D_
      </select>_x000D_
      <div>{{value}}_x000D_
      </div>_x000D_
    </div>_x000D_
  </div>_x000D_
</body>
_x000D_
_x000D_
_x000D_

Hope this could be useful for someone as it took me one day to find this solution on phonegap.


if the options are static, you could listen for the change event on your select box and add padding for each individual item

$('#id').change(function() {
    var select = $('#id');
    var val = $(this).val();

    switch(val) {
        case 'ValOne':
            select.css('padding-left', '30px');
            break;
        case 'ValTwoLonger':
            select.css('padding-left', '20px');
             break;
        default:
            return;
    }
});

2020, Im using:

select {
    text-align: center;
    text-align-last: center;
    -moz-text-align-last: center;
}

just using this:

select {

text-align-last: center;
padding-right: 29px;

}

There is a partial solution for Chrome:

select { width: 400px; text-align-last:center; }

It does center the selected option, but not the options inside the dropdown.


_x000D_
_x000D_
select {_x000D_
  text-align: center;_x000D_
  text-align-last: center;_x000D_
}_x000D_
option {_x000D_
  text-align: left;_x000D_
}
_x000D_
<select>_x000D_
   <option value="">(please select a state)</option>_x000D_
   <option class="lt" value="--">none</option>_x000D_
   <option class="lt" value="AL">Alabama</option>_x000D_
   <option class="lt" value="AK">Alaska</option>_x000D_
   <option class="lt" value="AZ">Arizona</option>_x000D_
   <option class="lt" value="AR">Arkansas</option>_x000D_
   <option class="lt" value="CA">California</option>_x000D_
   <option class="lt" value="CO">Colorado</option>_x000D_
</select>
_x000D_
_x000D_
_x000D_


On your select use width: auto and no padding to see how long your text is. I'm using 100% available width on my select and all of my options have the same length, this allows me to use very simple css.

text-indent will move the text from left, similar to padding-left
120px is my text length - I want to center it so take half of that size and half of the select size, leaving me with 50% - 60px

select{
  width: 100%;
  text-indent: calc(50% - 60px);
}

What if I have different sizes of options?

It is possible, however, the solution will not be a pretty one.
The former solution might get you really close to being centered if the difference between options isn't like 5 characters.

If you still need to center it more precisely you can do this

Prepare this class:

.realWidth{
   width: auto;
}

Apply onChange listener to select element

In that listener apply .realWidth to the select element with

const selectRef = document.getElementById("yourId");
selectRef.classList.add("realWidth");

Get access to the real width of the option.

const widthOfSelect = selectRef.getBoundingClientRect().width / 2;

widthOfSelect is the width you are looking for. Store it in global/component variable.

Remove the realWidth, you don't need it anymore.

selectRef.classList.remove("realWidth");

I am using react, I'm not sure this will work in vanilla, if not you have to find another solution.

<select style={`textIndent: calc(50% - ${widthOfSelect}) %`}> ... </select>

Another solution, however, that is a bad one could be creating the CSS classes with js and putting it to head.

PROS:

  1. probably works, I haven't tried the dynamic solution but it should work.

CONS:

  1. if the program is not fast enough user will see the width: auto taking place and thus wonder what's going on. If that is the case just create duplicate select, hide it behind something with a higher z-index and apply the on select listener from the original to the hidden duplicate.
  2. Might be hard to use if you cant inline the style because of vanilla limitation, but you can make a script to optimize the appendChild to the head.

I ran into this issue where a client was insisting on this, and they were on a Mac and and iPhone.

I wound up using media queries and a percentage padding for padding-left. Was this a satisfying solution? Not at all, but it let me move on.


Yes, it is possible. You can use text-align-last

text-align-last: center;

Not quite Centering but using example above you can make a left margin in select box.

<style>.UName { text-indent: 5px; }</style><br>

<select  name="UserName" id="UserName" size="1">
    <option class="UName" selected value="select">Select User</option>
    <option class="UName" value="User1">User 1 Name</option>
    <option class="UName" value="User2">User 2 Name </option>
    <option class="UName" value="User3">User 3 Name</option>
</select>

this worked for me:

text-align: center;
text-align-last: center;

You can't really customise <select> or <option> much. The only way (cross-browser) would be to manually create a drop down with divs and css/js to create something similar.