@radix-ui/themes
Version:
[](https://radix-ui.com/themes)
419 lines (354 loc) • 12.8 kB
CSS
.rt-TextFieldRoot {
display: flex;
align-items: stretch;
font-family: var(--default-font-family);
font-weight: var(--font-weight-regular);
font-style: normal;
text-align: start;
@supports selector(:has(*)) {
&:where(:has(.rt-TextFieldInput:focus)) {
outline: 2px solid var(--text-field-focus-color);
outline-offset: -1px;
}
}
@supports not selector(:has(*)) {
&:where(:focus-within) {
outline: 2px solid var(--text-field-focus-color);
outline-offset: -1px;
}
}
&::selection {
background-color: var(--text-field-selection-color);
}
}
.rt-TextFieldInput {
/*
* Flex layout edge case: when the parent container of TextFieldRoot
* is smaller than the intrinsic width of TextFieldInput with all the slots,
* this actually causes the input to shrink the available width.
*/
width: 100%;
/* Fix date inputs alignment in Chrome and Safari */
display: flex;
align-items: center;
/* Inherit alignment from root in case it's overriden */
text-align: inherit;
/*
* Hide type="number" input stepper because it's small, ugly, hard to use, and if
* needed, a nicer one can be easily implemented with own buttons in the Slot part.
*/
&:where([type='number']) {
-moz-appearance: textfield;
}
&::-webkit-inner-spin-button {
appearance: none;
}
/* Remove the native cancel button */
&::-webkit-search-cancel-button {
appearance: none;
}
&::selection {
background-color: var(--text-field-selection-color);
}
/*
* Style the date inputs:
* https://codepen.io/andresdamelio/pen/KKbvdYb
*/
/* Chrome’s calendar and time icons */
&::-webkit-calendar-picker-indicator {
box-sizing: content-box;
width: var(--text-field-native-icon-size);
height: var(--text-field-native-icon-size);
padding: var(--space-1);
margin-left: 0;
margin-right: calc(var(--space-1) * -1);
border-radius: calc(var(--text-field-border-radius) - 2px);
}
/* Chrome’s calendar icon */
&:where(:not([type='time']))::-webkit-calendar-picker-indicator {
margin-left: var(--space-1);
}
&::-webkit-calendar-picker-indicator:where(:hover) {
background-color: var(--gray-a3);
}
&::-webkit-calendar-picker-indicator:where(:focus-visible) {
outline: 2px solid var(--text-field-focus-color);
}
/* Remove focus ring from date fields and use the selection color */
&::-webkit-datetime-edit-ampm-field,
&::-webkit-datetime-edit-day-field,
&::-webkit-datetime-edit-hour-field,
&::-webkit-datetime-edit-millisecond-field,
&::-webkit-datetime-edit-minute-field,
&::-webkit-datetime-edit-month-field,
&::-webkit-datetime-edit-second-field,
&::-webkit-datetime-edit-week-field,
&::-webkit-datetime-edit-year-field {
&:where(:focus) {
background-color: var(--text-field-selection-color);
color: inherit;
outline: none;
}
}
@supports selector(:has(*)) {
&:where(:autofill, [data-com-onepassword-filled]) {
/* Reliably removes native autofill colors */
background-clip: text;
-webkit-text-fill-color: var(--gray-12);
}
}
}
.rt-TextFieldSlot {
box-sizing: border-box;
flex-shrink: 0;
display: flex;
align-items: center;
cursor: text;
/* A slot that is not a right-side slot goes on the left */
&:where(:not([data-side='right'])) {
order: -1;
margin-left: calc(var(--text-field-border-width) * -1);
margin-right: 0;
}
&:where([data-side='right']),
/*
* A slot followed by a left-side slot that is not a left-side slot itself goes on the right.
* In simple terms, this makes it so that two slots without an explicit side work automatically.
*/
:where(&:not([data-side='right'])) ~ &:where(:not([data-side='left'])) {
order: 0;
margin-left: 0;
margin-right: calc(var(--text-field-border-width) * -1);
}
}
/***************************************************************************************************
* *
* SIZES *
* *
***************************************************************************************************/
.rt-TextFieldRoot {
box-sizing: border-box;
height: var(--text-field-height);
padding: var(--text-field-border-width);
border-radius: var(--text-field-border-radius);
}
.rt-TextFieldInput {
/* Clip text to the border radius of the Root */
border-radius: calc(var(--text-field-border-radius) - var(--text-field-border-width));
/* Equivalent to padding-left, but doesn't cut off long values when cursor is at the end. */
text-indent: var(--text-field-padding);
&:where([type='date'], [type='datetime-local'], [type='time'], [type='week'], [type='month']) {
/* Safari is buggy with text-indent for these input types */
text-indent: 0;
padding-left: var(--text-field-padding);
padding-right: var(--text-field-padding);
}
/* Remove border-radius and text-indent/padding on the left if there’s a left-side slot */
&:where(:has(~ .rt-TextFieldSlot:not([data-side='right']))) {
text-indent: 0;
padding-left: 0;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/* Remove border-radius and padding on the right if there’s a right-side slot */
/* prettier-ignore */
&:where(:has(
~ .rt-TextFieldSlot[data-side='right'],
~ .rt-TextFieldSlot:not([data-side='right']) ~ .rt-TextFieldSlot:not([data-side='left'])
)) {
padding-right: 0;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
@breakpoints {
.rt-TextFieldRoot {
&:where(.rt-r-size-1) {
--text-field-height: var(--space-5);
--text-field-padding: calc(var(--space-1) * 1.5 - var(--text-field-border-width));
--text-field-border-radius: max(var(--radius-2), var(--radius-full));
--text-field-native-icon-size: var(--space-3);
font-size: var(--font-size-1);
letter-spacing: var(--letter-spacing-1);
& :where(.rt-TextFieldSlot) {
gap: var(--space-2);
padding-left: var(--space-1);
padding-right: var(--space-1);
}
& :where(.rt-TextFieldInput) {
/* Reset size 2 padding bottom */
padding-bottom: 0px;
/* Safari credentials autofill icon */
&::-webkit-textfield-decoration-container {
padding-right: 0px;
margin-right: -2px;
}
}
}
&:where(.rt-r-size-2) {
--text-field-height: var(--space-6);
--text-field-padding: calc(var(--space-2) - var(--text-field-border-width));
--text-field-border-radius: max(var(--radius-2), var(--radius-full));
--text-field-native-icon-size: var(--space-4);
font-size: var(--font-size-2);
letter-spacing: var(--letter-spacing-2);
& :where(.rt-TextFieldInput) {
/* Avoid 1px baseline jitter when layout around the text field is subpixel-sized (e.g. vh units). */
/* Works because as of Nov 2023, Chrome computes input text bounding box height as 16.5px on @2x screens. */
padding-bottom: 0.5px;
/* Safari credentials autofill icon */
&::-webkit-textfield-decoration-container {
padding-right: 2px;
margin-right: 0px;
}
}
& :where(.rt-TextFieldSlot) {
gap: var(--space-2);
padding-left: var(--space-2);
padding-right: var(--space-2);
}
}
&:where(.rt-r-size-3) {
--text-field-height: var(--space-7);
--text-field-padding: calc(var(--space-3) - var(--text-field-border-width));
--text-field-border-radius: max(var(--radius-3), var(--radius-full));
--text-field-native-icon-size: var(--space-4);
font-size: var(--font-size-3);
letter-spacing: var(--letter-spacing-3);
& :where(.rt-TextFieldInput) {
/* Reset size 2 padding bottom */
padding-bottom: 0px;
/* Safari credentials autofill icon */
&::-webkit-textfield-decoration-container {
padding-right: 5px;
margin-right: 0px;
}
}
& :where(.rt-TextFieldSlot) {
gap: var(--space-3);
padding-left: var(--space-3);
padding-right: var(--space-3);
}
}
}
}
/***************************************************************************************************
* *
* VARIANTS *
* *
***************************************************************************************************/
/* surface */
.rt-TextFieldRoot:where(.rt-variant-surface) {
--text-field-selection-color: var(--focus-a5);
--text-field-focus-color: var(--focus-8);
--text-field-border-width: 1px;
/* Blend inner shadow with page background */
background-clip: content-box;
background-color: var(--color-surface);
box-shadow: inset 0 0 0 var(--text-field-border-width) var(--gray-a7);
color: var(--gray-12);
& :where(.rt-TextFieldInput) {
&::placeholder {
color: var(--gray-a10);
}
}
& :where(.rt-TextFieldSlot) {
color: var(--gray-a11);
&:where([data-accent-color]) {
color: var(--accent-a11);
}
}
/* prettier-ignore */
&:where(:has(.rt-TextFieldInput:where(:autofill, [data-com-onepassword-filled]):not(:disabled, :read-only))) {
/* Blend with focus color */
background-image: linear-gradient(var(--focus-a2), var(--focus-a2));
box-shadow: inset 0 0 0 1px var(--focus-a5), inset 0 0 0 1px var(--gray-a5);
}
&:where(:has(.rt-TextFieldInput:where(:disabled, :read-only))) {
/* Blend with grey */
background-image: linear-gradient(var(--gray-a2), var(--gray-a2));
box-shadow: inset 0 0 0 var(--text-field-border-width) var(--gray-a6);
}
}
/* classic */
.rt-TextFieldRoot:where(.rt-variant-classic) {
--text-field-selection-color: var(--focus-a5);
--text-field-focus-color: var(--focus-8);
--text-field-border-width: 1px;
/* Blend inner shadow with page background */
background-clip: content-box;
background-color: var(--color-surface);
box-shadow: var(--shadow-1);
color: var(--gray-12);
& :where(.rt-TextFieldInput) {
&::placeholder {
color: var(--gray-a10);
}
}
& :where(.rt-TextFieldSlot) {
color: var(--gray-a11);
&:where([data-accent-color]) {
color: var(--accent-a11);
}
}
/* prettier-ignore */
&:where(:has(.rt-TextFieldInput:where(:autofill, [data-com-onepassword-filled]):not(:disabled, :read-only))) {
/* Blend with focus color */
background-image: linear-gradient(var(--focus-a2), var(--focus-a2));
box-shadow: inset 0 0 0 1px var(--focus-a5), inset 0 0 0 1px var(--gray-a5);
}
&:where(:has(.rt-TextFieldInput:where(:disabled, :read-only))) {
/* Blend with grey */
background-image: linear-gradient(var(--gray-a2), var(--gray-a2));
}
}
/* soft */
.rt-TextFieldRoot:where(.rt-variant-soft) {
--text-field-selection-color: var(--accent-a5);
--text-field-focus-color: var(--accent-8);
--text-field-border-width: 0px;
background-color: var(--accent-a3);
color: var(--accent-12);
& :where(.rt-TextFieldInput) {
&::placeholder {
color: var(--accent-12);
opacity: 0.6;
}
}
& :where(.rt-TextFieldSlot) {
color: var(--accent-12);
&:where([data-accent-color]) {
color: var(--accent-a11);
}
}
/* prettier-ignore */
&:where(:has(.rt-TextFieldInput:where(:autofill, [data-com-onepassword-filled]):not(:disabled, :read-only))) {
/* Use gray autofill color when component color is gray */
box-shadow: inset 0 0 0 1px var(--accent-a5), inset 0 0 0 1px var(--gray-a4);
}
&:where(:has(.rt-TextFieldInput:where(:disabled, :read-only))) {
background-color: var(--gray-a3);
}
}
/* all disabled and read-only text fields */
.rt-TextFieldInput {
&:where(:disabled, :read-only) {
cursor: text;
color: var(--gray-a11);
/* Safari */
-webkit-text-fill-color: var(--gray-a11);
&::placeholder {
opacity: 0.5;
}
&:where(:placeholder-shown) {
cursor: var(--cursor-disabled);
& ~ :where(.rt-TextFieldSlot) {
cursor: var(--cursor-disabled);
}
}
.rt-TextFieldRoot:where(:has(&)) {
--text-field-selection-color: var(--gray-a5);
--text-field-focus-color: var(--gray-8);
}
}
}