1 | # Button
|
2 | Handles buttons and button-like links (components that look like buttons, but
|
3 | behave as links) in the same uniform manner.
|
4 |
|
5 | [Examples](#examples)
|
6 |
|
7 | **Why?** — Sometimes we want a button to behave as an external or internal
|
8 | link, i.e. either to redirect a visitor to another resource, outside of the app,
|
9 | or to a different route, without reloading the app. Often there is also a need
|
10 | to switch between this and the regular button behavior, without changin the
|
11 | component look and layout. The `<Button>` component separates button styling
|
12 | from its logic, helping to conveniently handle them independently.
|
13 |
|
14 | Under the hood, a `<Button>` instance is rendered as:
|
15 | 1. A `<div>` block, when the button is disabled. It helps to ensure exactly the
|
16 | same style of disabled buttons and button-like links;
|
17 | 2. A [`<Link>`](link-and-navlink.md) component, when `to` property is set. This
|
18 | takes care about internal and external links.
|
19 | 3. A `<button>` element, otherwise. In principle, our `<Link>` component can
|
20 | play the button role as well, thus this third case could be avoided, but
|
21 | rendering true buttons with `<button>` elements is somewhat more efficient.
|
22 |
|
23 | ### Button Properties
|
24 | - **`active`** — *Boolean* — Optional. When *true*, the button is
|
25 | rendered in active state, even if it is not active otherwise;
|
26 | - **`disabled`** — *Boolean* — Optional. When *true*, the button is
|
27 | disabled;
|
28 | - **`enforceA`** — *Boolean* — Optional. When the button is rendered
|
29 | as `<Link>`, this prop enforces it to be rendered as a simple `<a>` element
|
30 | (external link);
|
31 | - **`onClick`** — *Function* — Optional. *onClick* event handler;
|
32 | - **`onMouseDown`** — *Function* — Optional. *onMouseDown* event
|
33 | handler;
|
34 | - **`opneNewTab`** — *Boolean* — Optional. When the button is
|
35 | rendered as `<Link>`, this property tells to open the link in a new tab;
|
36 | - **`replace`** — *Boolean* — Optional. When the button is rendered
|
37 | as `<Link>`, and the URL is internal, this property tells that the new route
|
38 | should replace the last record in the browser's history, rather than be pushed
|
39 | as a new entry into the history stack;
|
40 | - **`size`** — *String* — Optional. Button size. If specified, and
|
41 | `theme[size]` is defined, `theme[size]` class is added to the root element of
|
42 | the button. It is supposed to control button size, and although any values can
|
43 | be used, it is recommended to stick with `xs`, `sm`, `md`, `lg`, and `xl` size
|
44 | labels, with `md` size being the default, when no `size` property is passed in;
|
45 | - **`theme`** — *Object* — Button theme. This object is
|
46 | supposed to have the following fields:
|
47 | - **`button`** — *String* — The class to apply to the root element
|
48 | of the button in all cases;
|
49 | - **`disabled`** — *String* — The class to additionally apply to
|
50 | the root element of the button, when it is disabled;
|
51 | - **`link`** — *String* — Optional. The class to additionally
|
52 | apply to the root element of the button, when the button is rendered as
|
53 | `<Link>`;
|
54 | - **`regular`** — *String* — Optinal. The class to additionally
|
55 | apply to the root element of the button, when the button is rendered as
|
56 | `<button>`;
|
57 | - Other fields matching acceptable values of the `size` prop. Each of them
|
58 | will hold the class to additionally apply to the root element of the button,
|
59 | when the `<size>` value matches;
|
60 | - **`to`** — *Object* or *String* — When specified, the button will
|
61 | be rendered as `<Link>` (if non-disabled), and it will point to the specified
|
62 | URL/location.
|
63 | - **`type`** — *String* — Optional. Button type. It will have
|
64 | effect only when Button is rendered as `<button>`.
|
65 |
|
66 | ### <a name="examples">Examples</a>
|
67 | First of all, you want to define button theme, here is a good example to start from:
|
68 | ```scss
|
69 | // theme.scss
|
70 |
|
71 | /* Base button style (medium size). */
|
72 | .button {
|
73 | align-items: center;
|
74 | background: while;
|
75 | border: solid 1px black;
|
76 | color: black;
|
77 | display: inline-flex;
|
78 | font: normal 15px arial;
|
79 | justify-content: center;
|
80 | min-height: 40px;
|
81 | margin: 5px;
|
82 | padding: 5px 23px;
|
83 | vertical-align: middle;
|
84 | }
|
85 |
|
86 | /* Extra styling for the disabled buttons. */
|
87 | .disabled {
|
88 | cursor: not-allowed;
|
89 | opacity: 0.3;
|
90 | }
|
91 |
|
92 | /* .link and .regular classes are applied only to active buttons and button-like
|
93 | * links. Here we provide visual feedback for button "active", "focus", and
|
94 | * "hover" states. */
|
95 | .link,
|
96 | .regular {
|
97 | /* To ensure that visited button-like links look the same as the non-visited
|
98 | * ones (as typical buttons should not look different if they used to be clicked
|
99 | * before). */
|
100 | &:visited {
|
101 | color: black;
|
102 | font: normal 15px arial;
|
103 | }
|
104 |
|
105 | &:focus {
|
106 | box-shadow: 0 0 2px 1px #cfe6ff;
|
107 | border-color: #59a7ff;
|
108 | outline: none;
|
109 | }
|
110 |
|
111 | &:hover {
|
112 | background-image: linear-gradient(to top, #f5f5f5, white 49%, white);
|
113 | border-color: $tc-gray-40;
|
114 | }
|
115 |
|
116 | /* We need both ":active" selector and ".active" class here, if we want to
|
117 | * properly support the "active" option of the <Button>. */
|
118 | &.active,
|
119 | &:active {
|
120 | background-image: linear-gradient(to bottom, #f5f5f5, white 49%, white);
|
121 | box-shadow: inset 0 1px 2px 0 rgba(0, 0, 0, 0.2);
|
122 | border-color: $tc-gray-40;
|
123 | }
|
124 | }
|
125 |
|
126 | /* And a few extra classes to support "xs", "sm", and "lg" button sizes. */
|
127 | .xs {
|
128 | font: normal 11px arial;
|
129 | min-height: 20px;
|
130 | padding: 1px 13px;
|
131 | }
|
132 |
|
133 | .sm {
|
134 | font: normal 13px arial;
|
135 | min-height: 30px;
|
136 | padding: 4px 18px;
|
137 | }
|
138 |
|
139 | .lg {
|
140 | font: normal 17px arial;
|
141 | min-height: 50px;
|
142 | padding: 5px 28px;
|
143 | }
|
144 | ```
|
145 |
|
146 | You can apply this theme directly to your `<Button>`, but it is more
|
147 | convenient to use
|
148 | [react-css-super-themr](https://www.npmjs.com/package/react-css-super-themr)
|
149 | for management of the button default / context / and ad-hoc theming. To use it,
|
150 | you should wrap the `<Button>` component with `themr(..)` decorator:
|
151 | ```jsx
|
152 | // ThemedButton.js
|
153 | import { Button } from 'topcoder-react-utils';
|
154 | import { themr } from 'react-css-super-themr';
|
155 | import theme from './theme.scss';
|
156 |
|
157 | export default const ThemedButton = themr('ThemedButton', theme)(Button);
|
158 | ```
|
159 |
|
160 | Now you can use the button in your code in multiple ways:
|
161 | ```js
|
162 | import React from 'react';
|
163 | import { ThemeProvider } from 'react-css-super-themr';
|
164 | import Button from './ThemedButton';
|
165 |
|
166 | // Some themes we want to use for the ad-hoc and context theming.
|
167 | import adHocTheme from './adHocStyle.scss';
|
168 | import contextTheme from './contextTheme';
|
169 |
|
170 | export default function Example() {
|
171 | return (
|
172 | <div>
|
173 | <Button
|
174 | // Button with the default theme.
|
175 | onClick={() => console.log('Clicked!')}
|
176 | >Click Me!</Button>
|
177 |
|
178 | <Button
|
179 | // Button-like link with ad-hoc theming.
|
180 | theme={adHocTheme}
|
181 | to="https://www.topcoder.com"
|
182 | >Click Me!</Button>
|
183 |
|
184 | <ThemeProvider
|
185 | theme={{ ThemedButton: contextTheme }}
|
186 | >
|
187 | <Button
|
188 | // Button with context theming.
|
189 | onClick={() => console.log('Clicked!')}
|
190 | >Click Me!</Button>
|
191 | </ThemeProvider>
|
192 | </div>
|
193 | );
|
194 | }
|
195 | ```
|