Preview Updated 2026-05-10

Plain HTML / JS

Use ChuFix UI in projects without a build tool, Vue, or React. Pure HTML+JS gets you ~90% of the visual coverage via CSS classes alone.

ChuFix is CSS-first: every visual choice lives in a stylesheet keyed by cf-* class names. The component packages are just thin wrappers that string those classes together. Frameworks are optional — pull in the stylesheets and use <button class="cf-btn cf-btn--primary"> straight inside any plain HTML page.

Pull the CSS in

Two files are enough:

<!doctype html>
<html lang="en" data-theme="light">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <!-- 1. design tokens (colors, spacing, type, shadow, density) -->
    <link rel="stylesheet" href="https://unpkg.com/@chufix-design/tokens/src/tokens.css" />
    <!-- 2. all component class styles, bundled -->
    <link rel="stylesheet" href="https://unpkg.com/@chufix-design/vue/dist/style.css" />
    <title>ChuFix demo</title>
  </head>
  <body>

  </body>
</html>

Switch theme: change data-theme on <html> to dark-cool / dark-warm / light. Switch density: add data-density="compact".

CSS-only components (no JS needed)

These components carry no behavior — write the HTML and the styles take over.

Button

<button class="cf-btn cf-btn--primary">Primary</button>
<button class="cf-btn cf-btn--secondary">Secondary</button>
<button class="cf-btn cf-btn--tertiary">Tertiary</button>
<button class="cf-btn cf-btn--ghost">Ghost</button>
<button class="cf-btn cf-btn--danger">Danger</button>
<button class="cf-btn cf-btn--primary cf-btn--lg">Large</button>
<button class="cf-btn cf-btn--primary" disabled>Disabled</button>
<button class="cf-btn cf-btn--primary is-loading">Loading</button>

Input

cf-input is the wrapping label. cf-input__native is the actual <input>:

<label class="cf-input cf-input--outline cf-input--md">
  <input class="cf-input__native" type="text" placeholder="Enter…" />
</label>

<label class="cf-input cf-input--filled cf-input--md">
  <span class="cf-input__prefix">@</span>
  <input class="cf-input__native" type="email" placeholder="Email" />
</label>

Card

<article class="cf-card cf-card--elevated">
  <div class="cf-card__header">Title</div>
  <div class="cf-card__body">Body text goes here.</div>
  <div class="cf-card__footer">
    <button class="cf-btn cf-btn--primary cf-btn--sm">Confirm</button>
  </div>
</article>

Variants: cf-card--outlined / cf-card--elevated / cf-card--filled.

Tag / Badge / Avatar

<span class="cf-tag cf-tag--soft cf-tag--primary">Tag</span>
<span class="cf-tag cf-tag--solid cf-tag--success">OK</span>
<span class="cf-tag cf-tag--outline cf-tag--danger">Danger</span>

<span class="cf-badge cf-badge--danger">5</span>
<span class="cf-badge cf-badge--dot cf-badge--success"></span>

<span class="cf-avatar cf-avatar--md">CQ</span>
<span class="cf-avatar cf-avatar--lg cf-avatar--circle">
  <img src="/me.jpg" alt="" />
</span>

Alert

<div class="cf-alert cf-alert--info cf-alert--soft">
  <div class="cf-alert__body">
    <div class="cf-alert__title">An info notice</div>
    <div class="cf-alert__content">Supplementary text here.</div>
  </div>
</div>

Skeleton

<span class="cf-skeleton cf-skeleton--text" style="width: 200px;"></span>
<span class="cf-skeleton cf-skeleton--circle"></span>
<span class="cf-skeleton cf-skeleton--rect" style="width: 100%; height: 80px;"></span>

Checkbox / Radio / Switch

<label class="cf-checkbox cf-checkbox--md">
  <input type="checkbox" class="cf-checkbox__input" />
  <span class="cf-checkbox__box"></span>
  <span class="cf-checkbox__label">Accept terms</span>
</label>

<label class="cf-radio cf-radio--md">
  <input type="radio" name="r" class="cf-radio__input" />
  <span class="cf-radio__dot"></span>
  <span class="cf-radio__label">Option A</span>
</label>

<label class="cf-switch cf-switch--md">
  <input type="checkbox" class="cf-switch__input" />
  <span class="cf-switch__track"></span>
</label>

Components that need JS

Modal / Tooltip / Toast and similar need state or position math, so plain CSS isn’t enough. Two paths:

Path A: load Vue 3 from the ESM CDN

If your project has no bundler but you can drop in a <script type="module">, you can wire up Vue 3 + @chufix-design/vue via importmap:

<script type="importmap">
{
  "imports": {
    "vue": "https://esm.sh/vue@3",
    "@chufix-design/vue": "https://esm.sh/@chufix-design/vue@latest"
  }
}
</script>

<div id="app">
  <cf-button @click="show">Open</cf-button>
  <cf-modal v-model:open="open" title="Hello"><p>From ChuFix</p></cf-modal>
</div>

<script type="module">
  import { createApp, ref } from 'vue';
  import { CfButton, CfModal } from '@chufix-design/vue';

  createApp({
    components: { CfButton, CfModal },
    setup() {
      const open = ref(false);
      return { open, show: () => (open.value = true) };
    },
  }).mount('#app');
</script>

Path B: hand-roll a small vanilla JS shim

Modal / Tooltip / Toast already have their visuals defined in CSS; the only behavior to wire up is toggling a class:

<button id="open" class="cf-btn cf-btn--primary">Open</button>
<div id="modal" class="cf-modal" data-state="closed">
  <div class="cf-modal__backdrop"></div>
  <div class="cf-modal__panel cf-modal__panel--md">
    <header class="cf-modal__header">
      <h2 class="cf-modal__title">Title</h2>
      <button class="cf-modal__close" data-close>×</button>
    </header>
    <div class="cf-modal__body">Body.</div>
  </div>
</div>

<script>
  const m = document.getElementById('modal');
  document.getElementById('open').onclick = () => m.dataset.state = 'open';
  m.querySelectorAll('[data-close], .cf-modal__backdrop').forEach((el) =>
    el.addEventListener('click', () => (m.dataset.state = 'closed'))
  );
</script>

.cf-modal[data-state='open'] already drives the show/hide animation. Toggle data-state between 'open' and 'closed' and you’re done. Tooltip is similar — toggle visibility and compute position with getBoundingClientRect().

Minimal runnable example, no build tool

Drop the snippet below into a single index.html. Double-click in your browser:

<!doctype html>
<html lang="en" data-theme="dark-cool">
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="https://unpkg.com/@chufix-design/tokens/src/tokens.css" />
    <link rel="stylesheet" href="https://unpkg.com/@chufix-design/vue/dist/style.css" />
    <title>ChuFix · vanilla demo</title>
    <style>
      body { padding: 32px; max-width: 720px; margin: 0 auto; }
      .row { display: flex; gap: 8px; margin: 16px 0; flex-wrap: wrap; }
    </style>
  </head>
  <body>
    <h1>ChuFix · plain HTML demo</h1>

    <h2>Buttons</h2>
    <div class="row">
      <button class="cf-btn cf-btn--primary">Primary</button>
      <button class="cf-btn cf-btn--secondary">Secondary</button>
      <button class="cf-btn cf-btn--tertiary">Tertiary</button>
      <button class="cf-btn cf-btn--ghost">Ghost</button>
      <button class="cf-btn cf-btn--danger">Danger</button>
    </div>

    <h2>Form</h2>
    <label class="cf-input cf-input--outline">
      <input class="cf-input__native" type="text" placeholder="Nickname" />
    </label>

    <h2>Card</h2>
    <article class="cf-card cf-card--elevated">
      <div class="cf-card__header">Project settings</div>
      <div class="cf-card__body">ChuFix runs zero-dependency in plain HTML projects.</div>
      <div class="cf-card__footer">
        <button class="cf-btn cf-btn--primary cf-btn--sm">Save</button>
      </div>
    </article>

    <h2>Status</h2>
    <div class="cf-alert cf-alert--success cf-alert--soft">
      <div class="cf-alert__body">
        <div class="cf-alert__title">Ready</div>
        <div class="cf-alert__content">No npm, no webpack required.</div>
      </div>
    </div>
  </body>
</html>

Class cheat sheet

ComponentContainer classKey modifiers
Buttoncf-btn--primary / --secondary / --tertiary / --ghost / --danger; --sm / --lg; --pill / --square
Inputcf-input + inner cf-input__native--outline / --filled / --ghost; --sm / --lg
Textareacf-textarea + inner cf-textarea__nativesame
Cardcf-card--outlined / --elevated / --filled
Tagcf-tag--solid / --soft / --outline × --primary/success/warning/danger/info/neutral
Badgecf-badge--danger/--success and other tones; --dot
Avatarcf-avatar--sm/md/lg/xl; --circle/--square
Alertcf-alert--info/success/warning/error × --soft/outline/solid
Skeletoncf-skeleton--text/circle/rect
Checkboxcf-checkbox + inner cf-checkbox__input + cf-checkbox__box--sm/md/lg
Radiocf-radio + inner cf-radio__input + cf-radio__dot--sm/md/lg
Switchcf-switch + inner cf-switch__input + cf-switch__track--sm/md/lg
Tabscf-tabs + cf-tabs__list + cf-tabs__tab--line/segmented/pill; active item gets is-active

反馈与讨论

Plain HTML / JS · Discussion

0
0 / 600
一键发送
正在加载评论...