Skip to content

Instantly share code, notes, and snippets.

@pixelhandler
Last active December 21, 2015 14:39
Show Gist options
  • Save pixelhandler/6320922 to your computer and use it in GitHub Desktop.
Save pixelhandler/6320922 to your computer and use it in GitHub Desktop.
Ember.js component for a custom select box which can have a custom visual design and yet keep all standard browser behavior for selecting options. This `faux-select` is an Ember.Component which follows the intention of W3C web component draft for a "custom element"
App = Ember.Application.create();
App.Router.map(function() {
// put your routes here
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return {
name: 'one',
className: 'dropdown',
choices: [
{ choice: 'Choose One' },
{ choice: 'First' },
{ choice: 'Last' }
]
};
}
});
App.FauxSelectComponent = Ember.Component.extend({
selected: 'Choose One',
change: function(e){
this.set('selected', e.target.value);
}
});

Ember Components Example

  • With the select element using an opacity of zero (0), the element can have a custom background, and when clicking on the element the hidden select box still behaves normally (browser's default behavior)
  • The element with the class .faux-select-selected needs javascript functionality which updates the content binding to the value that is selected using the invisble select box (on change).

Steps to build a custom "faux" select box

(clone the emberjs/starter-kit to get started, see the components branch on this clone of starter kit...https://github.com/Ember-SC/starter-kit/commits/components)

  1. Start with removing the default index template/model from the emberjs/starter-kit
  2. Add a component template with a select box
  3. Use model for collection of choices
  4. Add some attributes and choices
  5. Scaffold markup and styles for faux select w/ zero opacity
  6. Add some custom style for the faux select box
  7. Bind the selected value and set min widths

Links

Styling Notes:

Below is a list of required styles for an example faux select box.

  • The select element has zero (0) opacity and is positioned absolute
  • The .faux-select-box element is also positioned absolute
  • The above two elements are siblings as the select box follows the faux element resulting in a higher z-index value, so when user clicks the event is fired on the invisble select box
  • the dimensions of the select box and faux select box need to match so the invisble element can be used on top of the faux element
<div class="faux-select">
  <div class="faux-select-box">
    <span class="faux-select-selected">{{selected}}</span>
    <span class="faux-select-graphic">&#x25BE;</span>
  </div>
  <select {{bindAttr name=name class=":faux-select className"}}>
  {{#each choices}}
    <option {{bindAttr value=choice}}>{{choice}}</option>
  {{/each}}
  </select>
</div>
/* FauxSelectComponent */
select.faux-select {
    display: block;
    opacity: 0;
    position: absolute;
    height: 20px;
    width: 125px;
    margin: 5px;
}
.faux-select {
    position: relative;
}
.faux-select-box {
    position: absolute;
    min-width: 137px;
}
.faux-select-selected,
.faux-select-graphic {
    height: 17px;
}
.faux-select-selected {
    float: left;
    min-width: 117px;
    padding: 5px 10px;
}
.faux-select-graphic {
    float: right;
    padding: 5px 7px;
}

Advantages

  • Native browser support for select/dropdown behavior including arrow keys, typing to select an option
  • Mobile devices still use finger friendly behaviour for select behaviors
  • Screen readers behave as expected with a standard select box
  • You don't have to fix all the bugs for taking over all the native brower support listed above and the custom select box can now match the designers branding needs

Disclaimer

The code in this example select box component has not been tested in various browsers and cross-browser css has not been included in the demo code. The concept of using 0 opacity for the selectbox does work in modern browsers.

Screenshot

Faux Select Box

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Ember Components</title>
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<script type="text/x-handlebars">
{{outlet}}
</script>
<script type="text/x-handlebars" id="index">
<h1>Components</h1>
{{faux-select choices=model.choices name=model.name className=model.className}}
</script>
<script type="text/x-handlebars" id="components/faux-select">
<h2>Faux Select</h2>
<div class="faux-select">
<div class="faux-select-box">
<span class="faux-select-selected">{{selected}}</span>
<span class="faux-select-graphic">&#x25BE;</span>
</div>
<select {{bindAttr name=name class=":faux-select className"}}>
{{#each choices}}
<option {{bindAttr value=choice}}>{{choice}}</option>
{{/each}}
</select>
</div>
</script>
<script src="js/libs/jquery-1.9.1.js"></script>
<script src="js/libs/handlebars-1.0.0.js"></script>
<script src="js/libs/ember-1.0.0-rc.7.js"></script>
<script src="js/app.js"></script>
</body>
</html>
/* FauxSelectComponent */
select.faux-select {
display: block;
opacity: 0;
position: absolute;
height: 20px;
width: 125px;
margin: 5px;
}
.faux-select {
color: black;
position: relative;
font: 14px/18px "Andale Mono", AndaleMono, monospace;
letter-spacing: 1px;
text-transform: uppercase;
}
.faux-select-box {
position: absolute;
min-width: 137px;
}
.faux-select-selected,
.faux-select-graphic {
background-image: linear-gradient(rgb(253, 250, 237), rgb(181, 203, 235));
border: 1px solid black;
height: 17px;
}
.faux-select-selected {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
border-right: none;
float: left;
min-width: 117px;
padding: 5px 10px;
}
.faux-select-graphic {
float: right;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
padding: 5px 7px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment