Skip to content

RFC: Consider component augmentation #403

@levithomason

Description

@levithomason

Dropdown

Copied from #401 regarding the icon prop. This conversation now applies to all Dropdown types.

Preliminary Findings

The Dropdown supports many variations, including rendering as a Button or a Menu Item. Here is what I've gathered that helped clarify some things for me:

  • There is only ever one icon
  • Dropdowns can appear as other components like a Button or a Menu Item
  • The icon is either a Dropdown icon, Button icon, or Menu Item icon but only one at a time

image

image

image

image

image

image

image

image

image

Brainstorming Solutions

Given the above, we may be able to use a single icon prop after all. It would just be applied to as either a Dropdown, Button, or Menu Item icon.

Our offline work going on with Forms may introduce a pattern that is helpful to Dropdowns as well. We may allow either component augmentation or specialized subcomponents in Form.Fields. This will facilitate our shorthand props API for Forms. Here are some of the ideas we are playing with:

<Form.Field control='input' type='password' label='Enter password:' />

<Form.Field control={Checkbox} label='I agree to the terms and conditions' />
// or
<Form.Checkbox label='I agree to the terms and conditions' />
<div class="field">
  <label>Enter password:</label>
  <input type='password' />
</div>

<div class="field">
  <Checkbox label='I agree to the terms and conditions' />
</div>

There is also a need library wide to explicitly set the element type for a component. Example, you may want to render a <Segment /> as an HTML <section />. We are considering a library wide standardized prop such as:

<Segment />
<Segment elementType='section' />
<div class="ui segment"></div>
<section class="ui segment"></section>

Applying it to the Dropdown

All of these ideas are ways of augmenting components. I have not thought this idea through at all, but it seems like we might support something along the lines of:

<Dropdown icon='filter' options={...} />
<Dropdown.Button labeled icon='settings' options={...} />
<Dropdown.Item icon='dropdown' options={...} />

// or

<Dropdown icon='filter' options={...} />
<Button elementType={Dropdown} labeled icon='settings' options={...} />
<Menu.Item elementType={Dropdown} icon='dropdown' options={...} />

The top group Dropdown.Item is already taken, so we'd have to solve the name conflict.

The latter group I think makes more sense. Consider the Button, all the props are regular button props (labeled, icon, etc) then the extra props (options) are passed to the Dropdown. This would result in a SUI dropdown being rendered with all the props/classes of both the Button and Dropdown.

As I write this, I'm thinking it might help users better understand the augmentation if we use the prop name as:

<Button as={Dropdown} labeled icon='settings' options={...} />
<Menu.Item as={Dropdown} icon='dropdown' options={...} />

// or

<Dropdown as={Button} labeled icon='settings' options={...} />
<Dropdown as={Menu.Item} icon='dropdown' options={...} />

MenuItem

Copied from https://github.com/TechnologyAdvice/stardust/pull/382#discussion_r75179898

Many other components and use cases have us considering the use of a library wide as prop:

<Segment as='section' />
//=> <section class="ui segment"></section>

<MenuItem as='a' />
//=> <a class="item></a>

<Dropdown as={Button} options={[...]} />
//=> <div class="ui button dropdown" />

Especially handy for react-router use with the MenuItem as it would allow passing props for both components:

import { Link } from 'react-router'

<MenuItem link as={Link} to='/home' activeClass='active' />
//=> <a class="item active"></a>

The MenuItem would consume its own props (link) and spread the rest. The as prop here means the MenuItem would render like:

render() {
  const ElementType = getElementType(props) // new util, like getUnhandledProps()

  return <ElementType {...rest} /* other menu item props */ />
}

The getElementType() method would hold the logic for returning the value of the as prop, else if props.link return a, else div. We could add more logic to how components are allowed to determine their element type as well. This is good because all components would be consistent.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions