To introduce a new Button component for YUI 3 that addresses the following user stories
- "I want buttons on my site to look consistent & attractive."
- "I want to be able to programmatically control buttons in my application."
- "I want to my buttons to be intelligent and interact with one another in groups."
- "I want my application to be able to dynamically generate buttons."
- ARIA / Accessibility
- Modern styles (using CSS3), but degrades well to legacy browsers
- Customizable colors with minimal fuss
- Something lighter than Y.Widget, but similar in features to YUI2 buttons
- cssbuttons (CSS) - Some lite CSS skins to give the buttons a nice look & feel. This is ideal for someone who just wants a nice looking button, without needing programatic control.
- button-base (JS) - A
Y.Attribute
-driven wrapper around a button-like DOM node, and some helper utilities - button-group (JS) - A manager that listens for Y.Button events and can fire notifications when the selection has changed
Buttons can be used in many different ways. Some users just want the buttons to be aesthetically pleasing, others want to listen for clicks/events, others want to programmatically control them, and some will use them for core navigation groups. Because of these variety of use cases, it's important to have functionality logically and modularly separate, while keeping them simple to use & control.
The lightest possible implementation is just including the button stylesheet and adding the yui3-button
class to any element you would like to be a button. As requirements start to increase, you can start adding on JS modules to provide the required functionality. The JS portion of Button is very Y.Attribute
-driven. The idea is that it that Y.Button
is basically a wrapper around a DOM node that fills in missing functionality and keeps the UI in sync with the button state. Y.ButtonGroup
is also Y.Attribute
driven that knows about groups of Y.Button
instances and manages them as a whole.
Y.Button
- The Y.Attribute-driven Button objectY.Buttons
- A way to generate an array of Y.Button instances given a NodeListY.ButtonGenerator
- A way to dynamically generate a Y.Button instance with an unattached DOM node
Y.ButtonGroup
- A way to connect Y.Button instances together and has a memory of selection states
- onClick
- getDOMNode
- _colorToHex (static)
- _getContrastYIQ (static)
- type - specifies the type of button (push/toggle)
- disabled - a setter for the node's 'disabled' attribute
- selected - a setter that handles the node's 'selected' state
- backgroundColor - The background color for the button
- typeChange
- selectedChange
- backgroundColorChange
- disabledChange
- yui3-button
- yui3-button:hover
- yui3-button:active
- yui3-button-selected
- yui3-button-focused
- yui3-button-disabled
- type - The type of group (default:push/radio/checkbox)
- buttons - An array of
Y.Button
instances that are in this group - selection - The array of
Y.Button
instances that are currently selected
- role=button
- aria-pressed
- aria-selected
I haven't come up with a good reason for making ARIA support optional (like YUI 2 Button), so it's just baked in for the time being.
You can find some demos here.
-
Y.Button
- Add sugar & properties to not require users to use .get() & .set() all the time. This will improve usability & performance. -
Y.Button
- Support aria-label/aria-labeledby -
Y.Button
- Support icons & image buttons -
Y.Button
- Determine if the color contrast calculation should belong inY.Button
, or elsewhere -
Y.Buttons
- Combine with Y.Button? -
Y.ButtonGenerator
- Allow an optionalcontainer
element that the node is appended to? -
Y.ButtonGroup
- Support aria-multiselectable for radio groups -
Y.ButtonGroup
- Possibly support aria-owns ifY.Button
instance relationship is not parent-children -
Y.ButtonGroup
- 'selection' is probably inefficient. -
cssbuttons
- Add basic Sam & Night skins -
Allow using selector strings as opposed to requiring a Node/NodeList to instantiate.
-
Investigate state on legacy browsers
-
Investigate state on tablets
-
Investigate lazy attributes
-
Use the
event-touch
module to be more responsive on touchscreen devicesY.all('.yui3-button').on(['touchstart' /* <- if applicable */, 'click'], function (e) { e.halt(); // Stop event propagation // do something });
"I don't understand what Y.Buttons is."
It's just a way to turn a
NodeList
intoY.Button
instances. This design isn't optimal for ease of use andY.Buttons
functionality will likely be merged intoY.Button
in the form of accepting a selection string,Node
, orNodeList
. Bigger fish to fry before I figure out a few issues with that though."And Y.ButtonGenerator seems like it could be a static method on Y.Button."
Sure.
Y.ButtonGenerator
vsY.Button.generate
is pretty trivial, and if we want to avoid creating newY
properties where possible, this seems like a good move."Do you think it would make sense to have ButtonGroup be an ArrayList implementation?"
I'll look into it.
"A push button class should have a configurable click/pressed handler."
Currently you can listen for any events with
Button.get('srcNode').on
. That certainly isn't ideal though, and improving that is just part of the sugar that I intend to add. My hesitation with baking it in during prototyping was what events do you support, and which ones does the user have to access the source Node to be able to use? There's also an issue withon('click', ...)
which it (by nature) fires too slow on touch devices (iPad 1, 200ms-500ms too slow by visual observation). So I think a ButtononClick
method should take this into consideration. See my mention of using event-touch in the Notes section."So ButtonGroup would bring custom CSS to the page, or is that also in cssbuttons?"
I haven't yet decided if cssbuttons.css is included/required with any of the JS modules. Do you include CSS by default, or not? We'll need to investigate this more. I'd lean towards we should if they
use('button')
, and if they don't want CSS, theyuse('button-base')
."So are you imagining all DOM rendering will be via the ButtonGenerator?"
It seems like that is the best way to go about it.
Y.ButtonGenerator
is very basic and really only there as a convenience. Ideally, the user would create the Node themselves and pass it intoY.Button
, but it seems like there should be some abstraction for generating a button."I think extending from Attribute instead of from Base is an interesting choice. Can you explain that?"
Initially I didn't even extend
Attribute
, but eventually ran into some issues thatAttribute
solved for me. I haven't run into any issues yet thatBase
solves, but I can certainly see that being the case asY.Button
is used with more complicated applications. The Keyboard example, for instance, was the latest one I created, and that really helped me understand howY.Button
could be used in real-world applications. There are still some changes I'd like to make because of things I discovered while hacking together that demo. I'd like to come up with a few more of these types of example applications, and I bet in doing so, I'll see the need for using Base. If you have any ideas, let me know." I imagine the Button API will be fairly small, so maybe mix it onto the Node instance directly. "
Mixing new properties directly into Node was my initial approach, and it worked nicely, but like you said, there are likely some philosophical issues with doing that. Also, perhaps some underlying issues that I'm not aware of. Maybe I'll whip up a prototype and send it out to the team to gather thoughts. As I mentioned in the gist,
Y.Button
is really just aAttribute
-based wrapper aroundNode
, so if it makes sense to just add additional properties ontoNode
(and grouping-related properties ontoNodeList
), that would be ideal.