Forms Theming
To make forms theming easy and robust, form components have many theming options in common.
General naming convention for CSS custom properties looks as follows:
--rui-FormField--[<TYPE>]--[<MODIFICATION>]__[<ELEMENT>--[<ELEMENT
TYPE]]--[<INTERACTION STATE>]__<PROPERTY>
Items in brackets are optional. As you read on you will notice some theming option groups may have less complicated conventions (that are still subset of the naming system above).
Basic Theming
The following theme options define basic appearance of all form fields.
Custom Property | Description |
---|---|
--rui-FormField__label__color |
Label text color |
--rui-FormField__label__font-size |
Label font size |
--rui-FormField__help-text__font-size |
Help text font size |
--rui-FormField__help-text__font-style |
Help text font style, e.g. italic |
--rui-FormField__help-text__color |
Help text color |
--rui-FormField--required__label__color |
Color of required input labels |
--rui-FormField--required__sign |
Text appended to required input labels |
--rui-FormField--required__sign__color |
Color of text appended to required input labels |
Horizontal Layout
Options for fields that support horizontal layout.
Custom Property | Description |
---|---|
--rui-FormField--horizontal__label__text-align |
Text alignment of labels in horizontal layout |
--rui-FormField--horizontal__label__min-width |
Minimum width of labels in horizontal layout |
--rui-FormField--horizontal__label__width |
Default width of labels in horizontal layout |
--rui-FormField--horizontal__label__padding-y |
Top and bottom padding to tweak vertical alignment of labels |
--rui-FormField--horizontal__label__vertical-alignment |
Vertical box alignment of labels in horizontal layout |
--rui-FormField--horizontal__field__vertical-alignment |
Vertical box alignment of fields in horizontal layout |
--rui-FormField--horizontal--full-width__label__width |
Default width of labels in full-width horizontal layout |
Box Fields
Options shared by box form controls. This includes TextField, TextArea, and SelectField.
Custom Property | Description |
---|---|
--rui-FormField--box__border-width |
Control border width |
--rui-FormField--box__border-radius |
Control corner radius |
--rui-FormField--box__input__width |
Default text input and select box width |
--rui-FormField--box__input__min-width |
Minimum text input and select box width |
--rui-FormField--box__placeholder__color |
Placeholder text color |
Example:
React.createElement(() => {
const [fruit, setFruit] = React.useState('apple');
const options = [
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
];
return (
<React.Fragment>
<style type="text/css">
{`
.example {
margin: 0;
}
.example > * {
margin: 4px;
}
.example--themed-form-fields {
--rui-FormField--box__border-width: 2px;
--rui-FormField--box__border-radius: 0.5rem;
--rui-FormField--box__input__width: 300px;
}
`}
</style>
<TextField
id="default-outline-text-field"
label="Default outline text field"
/>
<TextField
id="default-filled-text-field"
label="Default filled text field"
variant="filled"
/>
<SelectField
id="default-outline-select-field"
label="Default outline select field"
onChange={(e) => setFruit(e.target.value)}
options={options}
value={fruit}
/>
<div className="example example--themed-form-fields mt-6">
<TextField
id="themed-outline-text-field"
label="Themed outline text field"
/>
<TextField
id="themed-filled-text-field"
label="Themed filled text field"
variant="filled"
/>
<SelectField
id="themed-outline-select-field"
label="Themed outline select field"
onChange={(e) => setFruit(e.target.value)}
options={options}
value={fruit}
/>
</div>
</React.Fragment>
)
});
Box Field Variants
Theming options for box form controls. Naming convention looks as follows:
--rui-FormField--box--<VISUAL VARIANT>--<INTERACTION STATE>__<PROPERTY>
Where:
<VISUAL VARIANT>
is one offilled
oroutline
,<INTERACTION STATE>
is one ofdefault
,hover
,focus
, ordisabled
,<PROPERTY>
is one ofcolor
,border-color
,background
,box-shadow
, orsurrounding-text-color
(the last one being available only fordefault
anddisabled
interaction states).
Example:
React.createElement(() => {
const [fruit, setFruit] = React.useState('apple');
const options = [
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
];
return (
<React.Fragment>
<style type="text/css">
{`
.example {
margin: 0;
}
.example > * {
margin: 4px;
}
.example--themed-form-field-variants {
--rui-FormField--box__border-width: 0px;
--rui-FormField--box--outline--default__box-shadow:
0.1em 0.1em 0.5em rgba(0, 0, 0, 0.2);
--rui-FormField--box--outline--hover__box-shadow:
0.1em 0.1em 0.75em rgba(0, 0, 0, 0.3);
--rui-FormField--box--outline--focus__box-shadow:
inset 0.1em 0.1em 0.25em rgba(0, 0, 0, 0.2);
}
`}
</style>
<TextField
id="default-outline-text-field"
label="Default outline text field"
/>
<SelectField
id="default-outline-select-field"
label="Default outline select field"
onChange={(e) => setFruit(e.target.value)}
options={options}
value={fruit}
/>
<div className="example example--themed-form-field-variants mt-6">
<TextField
id="themed-outline-text-field"
label="Themed outline text field"
/>
<SelectField
id="themed-outline-select-field"
label="Themed outline select field"
onChange={(e) => setFruit(e.target.value)}
options={options}
value={fruit}
/>
</div>
</React.Fragment>
)
});
Box Field Sizes
Available sizes can be adjusted as follows:
--rui-FormField--box--<SIZE>__<PROPERTY>
Where:
<SIZE>
is one ofsmall
,medium
, orlarge
<PROPERTY>
is one ofheight
,padding-x
,padding-y
, orfont-size
👉 Box field sizes are linked to Button sizes so they align nicely when placed in row.
Example:
React.createElement(() => {
const [fruit, setFruit] = React.useState('apple');
const options = [
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
];
return (
<React.Fragment>
<style type="text/css">
{`
.example {
margin: 0;
}
.example > * {
margin: 4px;
}
.example--themed-form-field-sizes {
--rui-FormField--box--medium__height: 3rem;
--rui-FormField--box--medium__padding-x: 1.25rem;
}
`}
</style>
<TextField
id="default-medium-text-field"
label="Default medium text field"
/>
<SelectField
id="default-medium-select-field"
label="Default medium select field"
onChange={(e) => setFruit(e.target.value)}
options={options}
value={fruit}
/>
<div className="example example--themed-form-field-sizes mt-6">
<TextField
id="themed-medium-text-field"
label="Themed medium text field"
/>
<SelectField
id="themed-medium-select-field"
label="Themed medium select field"
onChange={(e) => setFruit(e.target.value)}
options={options}
value={fruit}
/>
</div>
</React.Fragment>
)
});
Check Fields
Options shared by checkable form controls. This includes CheckboxField, Radio, and Toggle.
Custom Property | Description |
---|---|
--rui-FormField--check__input__size |
Size of check inputs |
--rui-FormField--check__input__border-width |
Border width of check inputs |
--rui-FormField--check__input--focus__box-shadow |
Box shadow to highlight focused inputs |
--rui-FormField--check__tap-target-size |
Minimum tap target size |
Interaction states:
Custom Property | Description |
---|---|
--rui-FormField--check--default__border-color |
Border color of unchecked inputs |
--rui-FormField--check--default__check-background-color |
Background color of unchecked inputs |
--rui-FormField--check--checked__border-color |
Border color of checked inputs |
--rui-FormField--check--checked__check-background-color |
Background color of checked inputs |
--rui-FormField--check--disabled__border-color |
Border color of disabled unchecked inputs |
--rui-FormField--check--disabled__check-background-color |
Background color of disabled unchecked inputs |
--rui-FormField--check--checked-disabled__border-color |
Border color of disabled checked inputs |
--rui-FormField--check--checked-disabled__check-background-color |
Background color of disabled checked inputs |
Example:
React.createElement(() => {
const [agree, setAgree] = React.useState(true);
const [fruit, setFruit] = React.useState('apple');
const [studioQuality, setStudioQuality] = React.useState(true);
return (
<React.Fragment>
<style type="text/css">
{`
.example {
margin: 0;
}
.example > * {
margin: 4px;
}
.example--themed-check-fields {
--rui-FormField--check__input__border-width: 2px;
--rui-FormField--check--checked__border-color: LightSeaGreen;
--rui-FormField--check--checked__check-background-color: MediumAquamarine;
}
`}
</style>
<Radio
id="default-radio"
label="Default radio"
onChange={(e) => setFruit(e.target.value)}
options={[
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
]}
value={fruit}
/>
<CheckboxField
checked={agree}
id="default-checkbox"
label="Default checkbox"
onChange={() => setAgree(!agree)}
/>
<Toggle
checked={studioQuality}
id="default-toggle"
label="Default toggle"
onChange={() => setStudioQuality(!studioQuality)}
/>
<div className="example example--themed-check-fields mt-6">
<Radio
id="themed-radio"
label="Themed radio"
onChange={(e) => setFruit(e.target.value)}
options={[
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
]}
value={fruit}
/>
<CheckboxField
checked={agree}
id="themed-checkbox"
label="Themed checkbox"
onChange={() => setAgree(!agree)}
/>
<Toggle
checked={studioQuality}
id="themed-toggle"
label="Themed toggle"
onChange={() => setStudioQuality(!studioQuality)}
/>
</div>
</React.Fragment>
)
});
Validation States
Theming options for validation states are shared by all form components. Naming convention looks as follows:
--rui-FormField--<VALIDATION STATE>--<INTERACTION STATE>__<PROPERTY>
Where:
<VALIDATION STATE>
is one ofinvalid
,valid
, orwarning
<INTERACTION STATE>
is one ofdefault
,checked
,disabled
, orchecked-disabled
<PROPERTY>
is one ofcolor
,border-color
,background
,check-background-color
,box-shadow
, orsurrounding-text-color
Not all properties are used by all components, this varies from component to
component. Also, hover
interaction state is unavailable for validation states
everywhere — default
state appearance is retained on hovering. For box fields,
focus
state for validation states is inherited from default form field
appearance (i.e. as if no validation state was set).
Example:
React.createElement(() => {
const [agree, setAgree] = React.useState(true);
const [fruit, setFruit] = React.useState('apple');
const [studioQuality, setStudioQuality] = React.useState(true);
const options = [
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
];
return (
<React.Fragment>
<style type="text/css">
{`
.example {
margin: 0;
}
.example > * {
margin: 4px;
}
.example--themed-form-field-validation-states {
--rui-FormField--valid--default__color: white;
--rui-FormField--valid--default__border-color: LightSeaGreen;
--rui-FormField--valid--default__background: MediumAquamarine;
--rui-FormField--valid--default__check-background-color: MediumAquamarine;
--rui-FormField--valid--default__surrounding-text-color: DarkSlateGray;
--rui-FormField--valid--checked__check-background-color: MediumAquamarine;
}
`}
</style>
<TextField
id="default-valid-text-field"
label="Default valid text field"
validationState="valid"
validationText="This field is valid"
/>
<SelectField
id="default-valid-select-field"
label="Default valid select field"
onChange={(e) => setFruit(e.target.value)}
options={options}
validationState="valid"
validationText="This field is valid"
value={fruit}
/>
<Radio
id="default-valid-radio"
label="Default valid radio"
onChange={(e) => setFruit(e.target.value)}
options={[
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
]}
validationState="valid"
validationText="This field is valid"
value={fruit}
/>
<CheckboxField
checked={agree}
id="default-valid-checkbox"
label="Default valid checkbox"
onChange={() => setAgree(!agree)}
validationState="valid"
validationText="This field is valid"
/>
<Toggle
checked={studioQuality}
id="default-valid-toggle"
label="Default valid toggle"
onChange={() => setStudioQuality(!studioQuality)}
validationState="valid"
validationText="This field is valid"
/>
<div className="example example--themed-form-field-validation-states mt-6">
<TextField
id="themed-valid-text-field"
label="Themed valid text field"
validationState="valid"
validationText="This field is valid"
/>
<SelectField
id="themed-valid-select-field"
label="Themed valid select field"
onChange={(e) => setFruit(e.target.value)}
options={options}
validationState="valid"
validationText="This field is valid"
value={fruit}
/>
<Radio
id="themed-valid-radio"
label="Themed valid radio"
onChange={(e) => setFruit(e.target.value)}
options={[
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
]}
validationState="valid"
validationText="This field is valid"
value={fruit}
/>
<CheckboxField
checked={agree}
id="themed-valid-checkbox"
label="Themed valid checkbox"
onChange={() => setAgree(!agree)}
validationState="valid"
validationText="This field is valid"
/>
<Toggle
onChange={() => setStudioQuality(!studioQuality)}
checked={studioQuality}
id="themed-valid-toggle"
label="Themed valid toggle"
validationState="valid"
validationText="This field is valid"
/>
</div>
</React.Fragment>
)
});
Disabled State
By default, all disabled form fields are semi-transparent and change mouse cursor on hover so users know the fields cannot be used.
Custom Property | Description |
---|---|
--rui-FormField--disabled__cursor |
Cursor to show on hovering disabled form fields |
--rui-FormField--disabled__opacity |
Opacity of disabled form fields (inc. label and help text) |
Should your design require custom styling of disabled fields, individual field
types and validation states can be fine-tuned by several theming options
available. All you need is to define all necessary custom properties following
the naming conventions documented in previous sections (for simplicity, the
properties do not exist in the default theme, we only use transparency to mark
disabled fields by default). Namely, you will be interested in disabled
and
checked-disabled
interaction states and properties that are available for
styling of these states.
Example:
React.createElement(() => {
const options = [
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
];
return (
<React.Fragment>
<style type="text/css">
{`
.example {
margin: 0;
}
.example > * {
margin: 4px;
}
.example--themed-form-field-disabled-state {
/*_Common_*/
--rui-FormField--disabled__opacity: 1;
/*_Check fields_*/
--rui-FormField--check--disabled__border-color: silver;
--rui-FormField--check--disabled__check-background-color: gainsboro;
--rui-FormField--check--disabled__surrounding-text-color: silver;
--rui-FormField--check--checked-disabled__border-color: silver;
--rui-FormField--check--checked-disabled__check-background-color: gainsboro;
/*_Outline box fields_*/
--rui-FormField--box--outline--disabled__color: DarkGray;
--rui-FormField--box--outline--disabled__border-color: silver;
--rui-FormField--box--outline--disabled__background: gainsboro;
--rui-FormField--box--outline--disabled__surrounding-text-color: silver;
/*_Invalid state_*/
--rui-FormField--invalid--disabled__color: DarkGray;
--rui-FormField--invalid--disabled__border-color: silver;
--rui-FormField--invalid--disabled__background: gainsboro;
--rui-FormField--invalid--disabled__check-background-color: gainsboro;
--rui-FormField--invalid--disabled__surrounding-text-color: silver;
--rui-FormField--invalid--checked-disabled__check-background-color:
gainsboro;
/*_Warning state_*/
--rui-FormField--warning--disabled__color: DarkGray;
--rui-FormField--warning--disabled__border-color: silver;
--rui-FormField--warning--disabled__background: gainsboro;
--rui-FormField--warning--disabled__check-background-color: gainsboro;
--rui-FormField--warning--disabled__surrounding-text-color: silver;
--rui-FormField--warning--checked-disabled__check-background-color:
gainsboro;
/*_Valid state_*/
--rui-FormField--valid--disabled__color: DarkGray;
--rui-FormField--valid--disabled__border-color: silver;
--rui-FormField--valid--disabled__background: gainsboro;
--rui-FormField--valid--disabled__check-background-color: gainsboro;
--rui-FormField--valid--disabled__surrounding-text-color: silver;
--rui-FormField--valid--checked-disabled__check-background-color: gainsboro;
}
`}
</style>
<TextField
disabled
id="default-disabled-text-field"
label="Default disabled text field"
/>
<SelectField
disabled
id="default-disabled-select-field"
label="Default disabled select field"
options={options}
value="apple"
/>
<TextField
disabled
id="default-disabled-invalid-text-field"
label="Default disabled invalid text field"
validationState="invalid"
/>
<Radio
disabled
id="default-disabled-radio"
label="Default disabled radio"
options={[
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
]}
value="apple"
/>
<CheckboxField
checked
disabled
id="default-disabled-checkbox"
label="Default disabled checkbox"
/>
<Toggle
checked
disabled
id="default-disabled-toggle"
label="Default disabled toggle"
/>
<CheckboxField
disabled
id="default-disabled-warning-checkbox"
label="Default disabled warning checkbox"
validationState="warning"
/>
<Toggle
checked
disabled
id="default-disabled-valid-toggle"
label="Default disabled valid toggle"
validationState="valid"
/>
<div className="example example--themed-form-field-disabled-state mt-6">
<TextField
disabled
id="themed-disabled-text-field"
label="Themed disabled text field"
/>
<SelectField
disabled
id="themed-disabled-select-field"
label="Themed disabled select field"
options={options}
value="apple"
/>
<TextField
disabled
id="themed-disabled-invalid-text-field"
label="Themed disabled invalid text field"
validationState="invalid"
/>
<Radio
disabled
id="themed-disabled-radio"
label="Themed disabled radio"
options={[
{
label: 'Apple',
value: 'apple',
},
{
label: 'Banana',
value: 'banana',
},
{
label: 'Grapefruit',
value: 'grapefruit',
},
]}
value="apple"
/>
<CheckboxField
checked
disabled
id="themed-disabled-checkbox"
label="Themed disabled checkbox"
/>
<Toggle
checked
disabled
id="themed-disabled-toggle"
label="Themed disabled toggle"
/>
<CheckboxField
disabled
id="themed-disabled-warning-checkbox"
label="Themed disabled warning checkbox"
validationState="warning"
/>
<Toggle
checked
disabled
id="themed-disabled-valid-toggle"
label="Themed disabled valid toggle"
validationState="valid"
/>
</div>
</React.Fragment>
)
});