Skip to content

swiss-ui/vue

Repository files navigation

@swiss-ui/vue

Vue 3 components for the Swiss UI design system.

Installation

npm install @swiss-ui/vue vue

Architecture

Every component ships in two modes:

  • Headless (@swiss-ui/vue) — logic, state, ARIA, no CSS classes
  • Styled (@swiss-ui/vue/styled) — headless wrappers with swiss-* classes from @swiss-ui/core

Usage

Headless (default)

<script setup lang="ts">
import { SwissButton, SwissInput } from '@swiss-ui/vue'
</script>

<template>
  <SwissButton variant="solid" size="md">Submit</SwissButton>
  <SwissInput v-model="value" placeholder="Enter text" />
</template>

Styled

<script setup lang="ts">
import { SwissButton } from '@swiss-ui/vue/styled'
</script>

<template>
  <SwissButton variant="solid">Styled Button</SwissButton>
</template>

Global registration via plugin

import { createApp } from 'vue'
import { createSwissUI } from '@swiss-ui/vue/plugin'
import App from './App.vue'

const app = createApp(App)
app.use(createSwissUI({ prefix: 'Swiss' }))
app.mount('#app')

Plugin options:

Option Type Default Description
prefix string 'Swiss' Component name prefix. Pass '' to remove it
styled boolean false Register styled variants

Components

Primitives

Component Props Slots
SwissBox is default
SwissTextPrimitive is, size, weight, align, truncate default

Layout

Component Props Slots
SwissContainer size default
SwissStack gap, align, justify, direction default
SwissGrid cols, gap, align default
SwissGridItem colSpan, rowSpan default

Typography

Component Props Slots
SwissHeading is, level, size, weight, align default
SwissText is, size, weight, align, color, truncate default

Controls

Component Props Emits Slots
SwissButton is, variant, size, loading, disabled, type click default, leftIcon, rightIcon
SwissInput modelValue, size, disabled, invalid, type, placeholder update:modelValue, change, blur, focus leftAddon, rightAddon
SwissTextarea modelValue, resize, rows, autoResize, disabled, invalid update:modelValue, change, blur, focus
SwissSelect modelValue, size, disabled, invalid, placeholder update:modelValue, change, blur default (option elements)
SwissCheckbox modelValue, indeterminate, disabled, invalid, label, value update:modelValue, change default
SwissRadioGroup modelValue, name, disabled, orientation update:modelValue, change default
SwissRadio value, disabled, label default
SwissSwitch modelValue, disabled, label update:modelValue, change default

Feedback

Component Props Slots
SwissBadge variant, color default
SwissAlert variant icon, title, description, actions, default
SwissSpinner size, color, label

Overlay

Component Props Emits Slots
SwissModal open update:open, open, close default, portal
SwissModalOverlay default
SwissModalContent default
SwissModalHeader default
SwissModalBody default
SwissModalFooter default
SwissModalCloseButton default
SwissTooltip open, placement, delay, disabled, content update:open default (trigger), content
SwissDropdown open update:open, open, close default, portal
SwissDropdownTrigger default
SwissDropdownContent default
SwissDropdownItem disabled, onSelect select default
SwissDropdownSeparator
SwissDropdownLabel default

Examples

Modal

<script setup lang="ts">
import { ref } from 'vue'
import {
  SwissModal,
  SwissModalOverlay,
  SwissModalContent,
  SwissModalHeader,
  SwissModalBody,
  SwissModalFooter,
  SwissModalCloseButton,
  SwissButton,
} from '@swiss-ui/vue'

const open = ref(false)
</script>

<template>
  <SwissButton @click="open = true">Open Modal</SwissButton>

  <SwissModal v-model:open="open">
    <template #portal>
      <SwissModalOverlay>
        <SwissModalContent>
          <SwissModalHeader>
            <h2>Confirm Action</h2>
            <SwissModalCloseButton />
          </SwissModalHeader>
          <SwissModalBody>
            <p>Are you sure you want to continue?</p>
          </SwissModalBody>
          <SwissModalFooter>
            <SwissButton variant="ghost" @click="open = false">Cancel</SwissButton>
            <SwissButton variant="solid">Confirm</SwissButton>
          </SwissModalFooter>
        </SwissModalContent>
      </SwissModalOverlay>
    </template>
  </SwissModal>
</template>

Dropdown

<script setup lang="ts">
import {
  SwissDropdown,
  SwissDropdownTrigger,
  SwissDropdownContent,
  SwissDropdownItem,
  SwissDropdownSeparator,
} from '@swiss-ui/vue'
</script>

<template>
  <SwissDropdown>
    <SwissDropdownTrigger>Actions</SwissDropdownTrigger>
    <template #portal>
      <SwissDropdownContent>
        <SwissDropdownItem @select="handleEdit">Edit</SwissDropdownItem>
        <SwissDropdownItem @select="handleDuplicate">Duplicate</SwissDropdownItem>
        <SwissDropdownSeparator />
        <SwissDropdownItem :disabled="true">Delete</SwissDropdownItem>
      </SwissDropdownContent>
    </template>
  </SwissDropdown>
</template>

RadioGroup

<script setup lang="ts">
import { ref } from 'vue'
import { SwissRadioGroup, SwissRadio } from '@swiss-ui/vue'

const size = ref('md')
</script>

<template>
  <SwissRadioGroup v-model="size" name="size" orientation="horizontal">
    <SwissRadio value="sm" label="Small" />
    <SwissRadio value="md" label="Medium" />
    <SwissRadio value="lg" label="Large" />
  </SwissRadioGroup>
</template>

Vue Router integration

SwissButton accepts any component via :is, including RouterLink:

<script setup lang="ts">
import { RouterLink } from 'vue-router'
import { SwissButton } from '@swiss-ui/vue'
</script>

<template>
  <SwissButton :is="RouterLink" to="/dashboard" variant="link">
    Go to Dashboard
  </SwissButton>
</template>

Accessibility

All components follow WCAG 2.1 AA:

  • Keyboard navigable: Tab, Enter, Space, Arrow keys, Escape, Home, End
  • Proper ARIA roles: dialog, alert, switch, radiogroup, menu, menuitem, tooltip
  • Focus trap in SwissModal — focus stays inside the dialog while open
  • SwissSpinner includes a visible label via aria-label and <title>
  • SwissCheckbox supports indeterminate state via aria-checked="mixed"
  • SwissAlert uses aria-live="assertive" for errors, "polite" for others

SSR / Nuxt

Overlay components (SwissModal, SwissTooltip, SwissDropdown) use <Teleport to="body"> with an onMounted guard, making them safe for SSR. No document access happens during server-side rendering.

Build

npm run build      # compile to dist/
npm run test       # run Vitest
npm run typecheck  # vue-tsc check

About

Vue 3 components for the Swiss UI design system.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors