Direction:
Component demos
TL;DR
- Codex uses VitePress to demo components
- Run
npm run doc:dev
to serve the demo site locally - Each component should have a demo page. Demos should cover realistic use cases and variations of props and slots
- Demos are written in Markdown files in
packages/codex-docs/component-demos
then compiled topackages/codex-docs/docs/components
About the Codex docs site
Codex uses VitePress to demo Vue components. Component demos should provide working demonstrations and code samples for all realistic use cases of a component, plus all variations of props and slots. Ideally, a user of the library could copy and paste a code sample into their own code to use as a starting point.
Local dev environment
To serve the VitePress site locally, run this command in the root of the Codex repository:
bash
npm run doc:dev
This will both serve the VitePress site at http://localhost:5173
and compile component usage docs. If you need to serve the VitePress site on a different port, use npm run doc:dev --port=12345
. For ease of development, the site uses hot module reloading: changes to the source code are immediately reflected in the browser, without needing to reload the page.
Component page generation
Although most of the docs are simply markdown files within packages/codex-docs/docs
, the component page files in packages/codex-docs/docs/components
are automatically generated by vue-docgen-cli.
Component demos are written in markdown files outside of the packages/codex-docs/docs
directory (see below). vue-docgen-cli is configured to grab the demo file, add documentation that's generated from the component's .vue
file (page title, description, meta info, usage docs, etc.), and place the generated file in packages/codex-docs/docs/components
.
Writing component demos
Create a new demo page
Once you have a .vue
file for the component in packages/codex
, you can add a demo page for that component. This takes 2 steps:
- Add a new directory for your component to
packages/codex-docs/component-demos
. This new directory should exactly match the machine name of the component. Add a file,component-name.md
, to that directory. - Add a link to the page in the sidebar by editing VitePress config in
packages/codex-docs/docs/.vitepress/config.js
:
js
// In packages/codex-docs/docs/.vitepress/config.js
module.exports = {
themeConfig: {
sidebar: {
'/': [
...
{
text: 'Components',
items: [
// Add more components here.
{ text: 'Button', link: '/components/button' },
{ text: 'Radio', link: '/components/radio' }
]
},
...
]
}
}
}
Importing components
You can import Codex components directly from the @wikimedia/codex
package:
js
<script setup>
import { CdxButton } from '@wikimedia/codex';
</script>
Formatting demos
A cdx-demo-wrapper
component is available in all markdown files that provides some formatting for components demos and show code/hide code functionality. To use it, place the demo code inside the demo
slot, and the code sample inside the code
slot. The code can either be a markdown code block or an imported code snippet.
TIP
Note that the whitespace before and after the code sample is required for the markdown to compile properly.
Example using a markdown code block:
markdown
<cdx-demo-wrapper>
<template v-slot:demo>
<cdx-button type="quiet">Click me</cdx-button>
</template>
<template v-slot:code>
```vue-html
<cdx-button>Click me</cdx-button>
```
</template>
</cdx-demo-wrapper>
Example using an imported code snippet:
markdown
<script setup>
import RadioGroup from '@/../../component-demos/radio/examples/RadioGroup.vue';
</script>
<cdx-demo-wrapper>
<template v-slot:demo>
<radio-group />
</template>
<template v-slot:code>
<<< @/../../component-demos/radio/examples/RadioGroup.vue
</template>
</cdx-demo-wrapper>
Try to keep the code samples relevant to the library user. Remember that your code sample doesn't actually have to match the code used in the demo: for example, you might display an example component for the demo but include a simplified version of that example component to display as the code snippet.
Configurable demos
If a component has several variations depending on prop and slot input, it may benefit from a configurable demo that enables users to input different prop and slot values and see the results on the fly. This can be achieved within the Wrapper component, which can take in configuration for prop and slot controls, then provide the current values of those props and slots to the component demo via a scoped slot.
To set this up, create an array of config objects, one for each prop or slot you want to allow the user to control. The following control types are available:
radio
: for props with several known value options. Displays a radio for each provided value option.boolean
: For boolean props. Displays a true/false toggle that defaults to false.text
: For props with string or number values. Displays a text input for the value.slot
: For slots. Displays a text input for the slot content.
You can set a default value for each control (required for slots), otherwise the value will default to the first option (for radio
controls), false
(for boolean
controls), or an empty string (for text
controls)
See packages/codex-docs/docs/utils/types.ts
for full details on control configuration, or check out the configuration for the Button demo:
js
const controlsConfig = [
{
name: 'action',
type: 'radio',
options: [ 'default', 'progressive', 'destructive' ],
},
{
name: 'type',
type: 'radio',
options: [ 'normal', 'primary', 'quiet' ],
},
{
name: 'disabled',
type: 'boolean'
},
{
name: 'default',
type: 'slot',
default: 'Click me'
}
];
Next, set up the component demo. Pass the controls config to the Wrapper component via its controlsConfig
prop, then use the demo
slot with propValues
and slotValues
bindings to wrap your component demo. propValues
is an object keyed on prop name with the current value of each prop, and slotValues
is an object keyed on slot name with the current content of each slot. This is how the configurable Button demo is set up:
template
<cdx-demo-wrapper :controls-config="controlsConfig">
<template v-slot:demo="{ propValues, slotValues }">
<cdx-button v-bind="propValues">{{ slotValues.default }}</cdx-button>
</template>
</cdx-demo-wrapper>
Styling demo pages
Styles for a single demo page should be placed inside a <style>
block in the markdown file.
Styles for example components should be scoped to ensure they only apply to that component.