---
name: Component Guidance
route: /guidance-components/
---

import { Playground } from 'docz';
import { Content, Vertical, Horizontal, Responsive } from '../..'; 
import * as demos from '../../demos'; 

<demos.Star/>

# Component Concepts

> This section is in a [series of sections that provide further guidance for success][guidance].

Following the [sizing principle][principle-sizing] there are three categories of **defaults** you should follow in components 

- [Explicit Size](#explicit-size)
- [Content Sizing](#content-sizing)
- [Stretch Sizing](#stretch-sizing)

All of these can be supported by your component using [the `gls.component` function][component].

## Explicit Size 

> If a component exists to present an explicitly sized piece of information, then it should take explicit `SizeProps`.

Explicit size is rare, but still plays an active part in UI design. 

An example would be a profile display picture component where you want to set the width and the height to ensure the image takes up a particular space even before the image (content) is loaded. Notice the explicit `width` and `height` in the `style`

```ts
export const DemoProfile: React.FC<{ size: number }> = ({ size }) => {
  return (
    <img
      style={{
        borderRadius: '50%',
        // Explicit size
        width: `${size}px`,
        height: `${size}px`,
      }}
      src={`http://placekitten.com/g/${size}/${size}`} />
  );
}
```

<Playground>
  <demos.DemoProfile size={100}/>
</Playground>

## Content Sizing 
Content sizing is the most common form of sizing in designs out there. 

> If a component exists only to present the **dynamic amount of content** it contains, then it should be *content* by default.

You normally don't need to do anything special for the browsers to reliably size your items by content. Adding an explicit `sizing: 'content'` does help with flex-box bugs though and `gls.component` function does that. 

Examples: 
- Links (`a`)
- Buttons (`button`)
- Typography (`h1,h2,...,p,li,ul` etc)

## Stretch Sizing

> If a component is going to occupy a significant portion of user's interaction time, then it should be `sizing:'stretch'` by default. 
 
Examples:
- `input`
- `select` 
- `textarea`
- page body

As an example consider an input with `sizing:'stretch'` as default [using the `gls.component` function][component]:

```ts
export interface ExampleInputProps extends
  React.InputHTMLAttributes<HTMLInputElement>,
  gls.ComponentProps {
}

export const ExampleInput: React.FC<ExampleInputProps> = (props) => {
  const { className, ...otherProps } =
    gls.component(props, { sizing: 'stretch' });

  return <input className={className} {...otherProps} />
};
```

Such an input behaves nicely in common vertical, horizontal and responsive layouts: 

<Playground>
  <Vertical>
    <demos.DefaultInput placeholder="Example"/>
    <demos.DefaultInput placeholder="Example"/>
  </Vertical>
</Playground>

<Playground>
  <Horizontal>
    <demos.DefaultInput placeholder="Example"/>
    <demos.DefaultInput placeholder="Example"/>
  </Horizontal>
</Playground>

<Playground>
  <Responsive breakpoint={650}>
    <demos.DefaultInput placeholder="Example"/>
    <demos.DefaultInput placeholder="Example"/>
  </Responsive>
</Playground>

You can also provide a sizing ratio e.g. 1-2: 

<Playground>
  <Horizontal>
    <demos.DefaultInput placeholder="Example" sizing={1}/>
    <demos.DefaultInput placeholder="Example" sizing={2}/>
  </Horizontal>
</Playground>

An even explicit size if you need to, e.g. `width:200px`: 

<Playground>
  <Horizontal>
    <demos.DefaultInput placeholder="Example" sizing='content' width={200}/>
    <demos.DefaultInput placeholder="Example" sizing='content' width={200}/>
  </Horizontal>
</Playground>

[principle-sizing]:../principle-sizing/
[guidance]:../guidance/
[component]:../component/