Switch

Переключатель между двумя состояниями или состоянием включения‑выключения. Used for switching between two states or on‑off state.

Import Permalink to "Import"

js
import ProximaSwitch from 'proxima-vue/switch';

Playground Permalink to "Playground"

Props
Label position
View
Round
Shadow
Align
Click effect
js
import { ref } from 'vue';
import ProximaSwitch from 'proxima-vue/switch';

const value = ref(true);
html
<ProximaSwitch
  label="Check me"
  v-model="value"
/>

Custom values Permalink to "Custom values"

Вы можете указать любые true и false значения: You can specify any true and false values:

value: 'yes'
ts
import { ref } from 'vue';
import ProximaSwitch from 'proxima-vue/switch';

const value = ref('yes');
html
<ProximaSwitch
  label="Check me"
  true-value="yes"
  false-value="no"
  v-model="value"
/>

Multiple Permalink to "Multiple"

Переключатель будет добавлять/удалять true‑value из массива: The switch will add/remove true‑value from the array:

value: []
js
import { ref } from 'vue';
import ProximaSwitch from 'proxima-vue/switch';

const value = ref([]);
html
<ProximaSwitch
  label="Check one"
  true-value="one"
  v-model="value"
/>

<ProximaSwitch
  label="Check two"
  true-value="two"
  v-model="value"
/>

Text and icon Permalink to "Text and icon"

В специальные слоты checked и unchecked можно передать иконки или текст: You can specify icons or text to special checked and unchecked slots:

js
import { ref } from 'vue';
import ProximaSwitch from 'proxima-vue/switch';
import ProximaIconCheck from 'proxima-vue/icon/check';
import ProximaIconCross from 'proxima-vue/icon/cross';

const value = ref(false);
html
<ProximaSwitch
  label="Check me"
  v-model="value"
>
  <template #checked>YES</template>
  <template #unchecked>NO</template>
</ProximaSwitch>

<ProximaSwitch
  label="Check me"
  v-model="value"
>
  <template #checked>
    <ProximaIconCheck />
  </template>
  <template #unchecked>
    <ProximaIconCross />
  </template>
</ProximaSwitch>

Pending Permalink to "Pending"

Режим ожидания во время запроса: Pending mode on request:

js
import { ref } from 'vue';
import ProximaSwitch from 'proxima-vue/switch';
import ProximaSpinner from 'proxima-vue/spinner';

const isPending = ref(true);
html
<ProximaSwitch
  label="Check me"
  :inert="isPending"
>
  <template #thumb>
    <ProximaSpinner v-if="isPending" />
  </template>
</ProximaSwitch>

Skeleton Permalink to "Skeleton"

Режим плейсхолдера во время загрузки: Placeholder mode on loading:

Атрибут data‑ghost требует The attribute data‑ghost requires ghost.css

html
<div data-ghost="true" inert>
  <ProximaSwitch
    label="Check me"
  />
</div>

Indeterminate Permalink to "Indeterminate"

Специальный пропс для состояния indeterminate: A special prop for indeterminate state:

value: ''
js
import { ref } from 'vue';
import ProximaSwitch from 'proxima-vue/switch';

const value = ref('');
html
<ProximaSwitch
  label="Do you want to enable notifications?"
  true-value="yes"
  false-value="no"
  :indeterminate="value === ''"
  v-model="value"
/>

Accessibility Permalink to "Accessibility"

Компонент использует checkbox поле с role="switch", оно скрыто визуально, но доступно для вспомогательных технологий, для описания поля используется label, его также можно визуально скрыть: The component uses checkbox input with role="switch", it is hidden visually, but available for assistive technologies, a label is used to describe the input, it can also be visually hidden:

Для работы visually‑hidden требуется The prop visually‑hidden requires accessibility.css

html
<ProximaSwitch
  label="Label only for assistive technologies"
  label-visually-hidden
/>

Если же требуется расширенное описание, то можно использовать пропс describedby, который добавляет полю атрибут aria‑describedby: If you need an extended description, you can use the describedby prop, which adds aria‑describedby attribute to the input:

html
<ProximaSwitch
  label="Check me"
  describedby="my-hidden-description"
/>

<p id="my-hidden-description" hidden>
  The extended description for assistive technologies can be hidden
</p>

BEM Permalink to "BEM"

Блок компонента switch, модификаторы (создаются автоматически на основе пропсов): Component block switch, modifiers (automatically created based on props):

CSS Permalink to "CSS"

Слой компонента @layer proxima.switch, также вы можете гибко cтилизовать компонент через кастомные свойства: Component layer @layer proxima.switch, also you can style the component flexibly through custom properties:

css
--switch-background: #bfbfbf;
--switch-value-color: #fff;
--switch-accent-color: var(--app-accent-color);

--switch-min-width-multiplier: 1.85;
--switch-min-width: calc(
  var(--switch-size) * var(--switch-min-width-multiplier) -
  var(--switch-padding)
));
--switch-gap: calc(var(--switch-size) / 2);
--switch-transition: background-color 200ms ease;

/* Soft round */
--switch-border-radius: calc(var(--switch-size) / 4);

/* Spinner and icon */
--switch-spinner-size: 72%;
--switch-icon-size: 80%;

/* Effect */
--switch-effect-pulse-color: var(--switch-background);
--switch-effect-ripple-color: #000;
--switch-effect-z-index: 2;

/* Slider view */
--switch-track-margin-y: 25%;
--switch-track-margin-x: var(--switch-padding);

/* Border */
--switch-border-width: 0;
--switch-border-style: solid;
--switch-border-color: transparent;

/* Label */
--switch-label-line-height: 1.3;
--switch-label-color: var(--app-label-color);
--switch-label-align-self: center;

/* Thumb */
--switch-thumb-background: #fff;
--switch-thumb-color: #000;
--switch-thumb-padding: 0;
--switch-thumb-border-radius: inherit;
--switch-thumb-box-shadow: 0 0.125rem 0.25rem 0 rgba(0, 0, 0, 0.2);
--switch-thumb-transition: inset 250ms cubic-bezier(0.22, 1, 0.36, 1);

/* Value */
--switch-value-color: #fff;
--switch-value-padding-x: 1em;
--switch-value-padding-y: 0;
--switch-value-transition: transform 250ms cubic-bezier(0.22, 1, 0.36, 1);

/* Shadow */
--switch-box-shadow-soft-size: 0 0.0625rem 0.25rem;
--switch-box-shadow-soft-color: rgba(0, 0, 0, 0.15);

/*
  States
*/

/* Checked */
--switch-checked-background: var(--switch-accent-color);
--switch-checked-value-color: var(--switch-value-color);
--switch-checked-thumb-background: var(--switch-thumb-background);
--switch-checked-thumb-color: var(--switch-thumb-color);

/* Hover */
--switch-hover-mix-color: #000;
--switch-hover-mix-opacity: 0.1;
--switch-hover-background: color-mix(in srgb,
  var(--switch-background), var(--switch-hover-mix-color) var(--switch-hover-mix-opacity)
);

/* Disabled */
--switch-disabled-opacity: var(--app-disabled-opacity);
--switch-disabled-background: var(--switch-background);
--switch-disabled-thumb-background: var(--switch-thumb-background);

/* Focus highlight */
--switch-highlight-offset: var(--app-highlight-offset);
--switch-highlight-style: var(--app-highlight-style);
--switch-highlight-size: var(--app-highlight-size);
--switch-highlight-color: var(--app-highlight-color);

/* Tab focus outline */
--switch-outline-offset: var(--app-outline-offset);
--switch-outline-size: var(--app-outline-size);
--switch-outline-style: var(--app-outline-style);
--switch-outline-color: var(--app-outline-color);

/*
  Sizes
*/

--switch-size-xxs: 1rem;
--switch-padding-xxs: 0.125rem;
--switch-label-font-size-xxs: 0.75rem;
--switch-value-font-size-xxs: 0.625rem;
--switch-state-icon-size-xxs: 0.5rem;

--switch-size-xs: 1.125rem;
--switch-padding-xs: 0.125rem;
--switch-label-font-size-xs: 0.8125rem;
--switch-value-font-size-xs: 0.625rem;
--switch-state-icon-size-xs: 0.5rem;

--switch-size-s: 1.25rem;
--switch-padding-s: 0.125rem;
--switch-label-font-size-s: 0.875rem;
--switch-value-font-size-s: 0.625rem;
--switch-state-icon-size-s: 0.5rem;

/* Normal */
--switch-size: 1.375rem;
--switch-padding: 0.125rem;
--switch-label-font-size: 0.875rem;
--switch-value-font-size: 0.75em;
--switch-state-icon-size: 0.625rem;

--switch-size-m: 1.625rem;
--switch-padding-m: 0.1875rem;
--switch-label-font-size-m: 1rem;
--switch-value-font-size-m: 0.875rem;
--switch-state-icon-size-m: 0.625rem;

--switch-size-l: 1.875rem;
--switch-padding-l: 0.25rem;
--switch-label-font-size-l: 1.125rem;
--switch-value-font-size-l: 0.875rem;
--switch-state-icon-size-l: 0.75rem;

--switch-size-xl: 2.25rem;
--switch-padding-xl: 0.25rem;
--switch-label-font-size-xl: 1.25rem;
--switch-value-font-size-xl: 1rem;
--switch-state-icon-size-xl: 0.875rem;

--switch-size-xxl: 2.5rem;
--switch-padding-xxl: 0.25rem;
--switch-label-font-size-xxl: 1.375rem;
--switch-value-font-size-xxl: 1.125rem;
--switch-state-icon-size-xxl: 1rem;

/*
  Flags (0 or 1, based on props)
*/
--switch-has-effect: 0;

--switch-is-view-plain: 0;
--switch-is-view-slider: 0;

--switch-is-checked: 0;
--switch-is-unchecked: 0;
--switch-is-indeterminate: 0;
--switch-is-disabled: 0;

--switch-is-focus: 0;
--switch-is-hover: 0; /* ! */
--switch-is-active: 0; /* ! */

/*
  [!] Available for .switch__content not on .switch
*/
Theme Permalink to "Theme"

Используя кастомные свойства и специальный пропс theme можно легко создавать свои темы: By using custom properties and the prop theme, you can easily create your own themes:

html
<ProximaSwitch
  label="Check me"
  theme="ios"
/>
css
.switch_theme_ios {
  --switch-label-color: #8d8d92;
  --switch-background: #dfdfe0;
  --switch-value-color: #b8b8b8;
  --switch-checked-value-color: #fff;
  --switch-accent-color: #35c759;
  --switch-thumb-box-shadow: 0 0.125rem 0.125rem rgba(0, 0, 0, 0.1);
  --switch-min-width-multiplier: 1.75;
  --switch-hover-mix-opacity: 0.05;
}
Locale Permalink to "Locale"

Компонент использует токены локализации: The component uses localization tokens:


js
{
  switchRequired: "The switch must be activated",
}
Props Permalink to "Props"
ts
interface ProximaSwitchProps {
  id?: string
  inputAttrs?: InputHTMLAttributes
  trueValue?: any
  falseValue?: any
  modelValue?: any
  label?: string
  labelPosition?: 'before' | 'after'
  labelVisuallyHidden?: boolean
  describedby?: string
  hasStateIcons?: boolean
  disabled?: boolean
  required?: boolean
  indeterminate?: boolean
  align?: ProximaAlign
  view?: 'plain' | 'slider'
  size?: ProximaSize
  round?: ProximaRound
  shadow?: ProximaShadow
  effect?: ProximaClickEffect
  theme?: string
}
Events Permalink to "Events"
html
<ProximaSwitch
  @update:modelValue="onSwitchUpdate"
  @focus="onSwitchFocus"
  @blur="onSwitchBlur"
/>
js
const onSwitchUpdate = (modelValue) => {};
const onSwitchFocus = (event) => {};
const onSwitchBlur = (event) => {};
ts
type Emits = {
  'update:modelValue': (modelValue: any) => void
  'focus': (event: FocusEvent) => void
  'blur': (event: FocusEvent) => void
}
Slots Permalink to "Slots"
html
<ProximaSwitch>
  <template #prepend="slotProps">
    you code (prepend to content)
  </template>

  <template #checked="slotProps">
    you code (visible when checked)
  </template>

  <template #unchecked="slotProps">
    you code (visible when unchecked)
  </template>

  <template #thumb="slotProps">
    you code (append to thumb)
  </template>

  <template #label="slotProps">
    you code (replaced label text)
  </template>
</ProximaSwitch>
ts
type SlotProps = {
  id: string
  hasEffect: boolean
  hasLabel: boolean
  hasUncheckedValue: boolean
  hasCheckedValue: boolean
  hasStateIcons: boolean
  isIndeterminate: boolean
  isMultiple: boolean
  isChecked: boolean
  isFocused: boolean
  isValid: boolean
  errorMessage: string
  value: any
  focus: () => void
  blur: () => void
}
Expose Permalink to "Expose"
html
<ProximaSwitch ref="switcher" />
ts
import { ref, unref, onMounted } from 'vue';
import ProximaSwitch from 'proxima-vue/switch';

const switcher = ref({} as InstanceType<typeof ProximaSwitch>);

onMounted(() => {
  unref(switcher).checkFocus(); // false
  unref(switcher).focus();
  unref(switcher).checkFocus(); // true
});
ts
type ProximaSwitchInstance = {
  getErrorMessage: () => string
  getContainer: () => HTMLDivElement | null
  getElement: () => HTMLInputElement | null
  getValue: () => any
  getId: () => string
  checkValidity: () => boolean
  checkFocus: () => boolean
  checked: () => boolean
  focus: () => void
  blur: () => void
}
View source on GitHub