/vue-tabs

Proof-of-concept tabbed UI component built with Vue 3 and Vite

Primary LanguageVue

Vue-Tabs Demo Component

This repo is an experiment in how to develop UI components with Vue 3 and Vite. Other technologies like PostCSS and Typescript may also come into play.

Usage

# install the dependencies
yarn install

# run the dev server
yarn run dev

# build static files
yarn run build

Other Notes

PostCSS

PostCSS is being used to transpile certain future CSS features (custom properties, nested rulesets) into backwards-compatible code.

Vite can support PostCSS automatically, but a series of plugins are needed for the transformations. They are defined and configured in postcss.config.js.

This allows Vue SFCs to include style tags like this:

<style lang="postcss">
@import 'wikimedia-ui-base/wikimedia-ui-base.css';
.vue-tabs {
	&__header {
		align-items: flex-end;
		box-shadow: inset 0 -1px 0 0 var(--border-color-base);
		display: flex;
		justify-content: space-between;
	}
}
</style>

If other features are needed (like @apply), just add the appropriate plugin.

Script Setup

Components are written using the Composition API and <script setup>, which is Vue3's recommended way of doing things when you are using both SFCs and the new API: https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup

All variables in the top-level scope are visible to the template; there is no need to define a function that returns them. Some compiler macros are also available here (defineProps, defineEmits, etc.); these don't need to be imported and are transformed at compile-time into equivalent code; they aren't available at runtime.

Type definitions for JavaScript

It is possible to use TypeScript types in plain JavaScript projects; this code will attempt to demonstrate an approach to doing this.

A TypeScript definitions file lives at src/types.d.ts. This file exports some interfaces as in a standard TS project:

export interface TabData {
	id: string,
	label: string,
	isActive: boolean,
	disabled: boolean
}

Inside the JavaScript Vue components, it is possible to get type hinting in VSCode (and likely many other editors) by "importing" these types in JSDoc @type tags:

/**
 * @type {import("../types").TabData}
 */
const tab = reactive( inject( 'tabsData' )[ props.id ] );

Finally, for an extra level of type-checking, add a // @ts-check comment at the top of the file (or the script tag of a Vue SFC).

With that line added, a properly-configured error will flag a line like:

const bar = tab.bar

// => "Property 'bar' does not exist on type 'TabData'."

Since these features come from the editor itself, there is no need to add a TypeScript dependency to package.json unless additional functionality is needed.

Build Configuration

This demo uses Vite's Library Mode feature to generate files for distribution. This feature allows easy generation of bundles in multiple formats (UMD, ESM, CJS, IIFE). An alternate src/lib.js entry point has been provided that exports only the components themselves, not any of the demo scaffolding or the public index.html file.

  • Tree-shaking happens by default (any unused code will be eliminated from build)
  • Vue component templates are compiled into render functions
  • CSS is compiled into a separate stand-alone file that only includes component style rules and inlined variables that were used (see CSS next config for details)
  • Vue.js itself has been externalized and will not be included in the build.

Here's what gets generated currently:

dist/vue-tabs.style.css		0.74 KiB / brotli: 0.25 KiB
dist/vue-tabs.es.js		2.24 KiB / brotli: 0.96 KiB
dist/vue-tabs.cjs.js		2.43 KiB / brotli: 0.93 KiB