npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue-formless

v0.2.0

Published

Vue 3 表单组合式 hooks

Readme

vue-formless

简体中文 | English

Vue 3 表单组合式库:控件表 + FormView,布局与输入拆开。当前 0.2.0,0.x 期间 API 仍可能调整。

同一套混合布局:左边手写 Element Row/Col/Item,右边 <User.*> + 嵌套 FormView 换密度。

混合布局代码对照

Playground 平铺对比(布局对齐):

混合布局平铺对比

pnpm add vue-formless
# 或 npm i vue-formless

peer:vue ^3.3。

用法

项目里绑一次宿主(无官方 Element 适配包):

import { ElCol, ElForm, ElFormItem, ElInput, ElRow } from 'element-plus'
import { defineComponent, h, ref, type PropType } from 'vue'
import { createFormFields, createFormView, type FormFieldFormless } from 'vue-formless'

declare module 'vue-formless' {
  interface FormFieldCustomOptions {
    label?: string
  }
}

// ElFormItem 的 `prop` 用点分路径;内核位置(`buyers[0].name`)由本层编码(design.md §20.9)。
// 一个宿主 `prop` 装不下多个口 → 多口一格不绑宿主(`undefined`),
// 需要宿主校验就用 `fl:field="wrap-embed"` 拆成一格一口。
function toItemProp(prop: FormFieldFormless['prop']): string | undefined {
  if (prop == null || prop.length !== 1) return undefined
  const [location] = prop
  if (location == null) return undefined
  const dotted = location.replace(/\[(\d+)\]/g, '.$1').replace(/^\./, '')
  if (!dotted || /[[\]]/.test(dotted)) return undefined // 编不出来:不绑宿主
  return dotted
}

// 无前缀的写口 `modelValue` 按 no-prefix 规则透传到宿主 Form,而 ElForm 的 model
// 口叫 `model`:适配层用一个 MyForm 包住 ElForm 完成映射,并把 ElForm 实例的
// validate / resetFields 透出给 FormView 的 ref 代理。工厂不再接受 form.props 函数。
const MyForm = defineComponent({
  inheritAttrs: false,
  props: { modelValue: { type: [Object, Array] as PropType<unknown>, default: undefined } },
  setup(props, { attrs, slots, expose }) {
    const form = ref<Record<string, unknown> | null>(null)
    expose(new Proxy({}, {
      get: (_, key) => {
        const inner = form.value
        if (inner == null) return undefined
        const value = Reflect.get(inner, key, inner)
        return typeof value === 'function' ? value.bind(inner) : value
      },
      has: (_, key) => form.value != null && key in form.value,
    }))
    return () => h(ElForm, { ...attrs, ref: form, model: props.modelValue }, slots)
  },
})

export const FormView = createFormView({
  layout: { Row: ElRow, Col: ElCol, props: { column: 2 } },
  form: { component: MyForm },
  item: {
    component: ElFormItem,
    props: (fl: FormFieldFormless) => ({
      label: fl.label,
      prop: toItemProp(fl.prop),
    }),
  },
})

export const User = createFormFields({
  name: { label: '姓名', component: ElInput },
})
<FormView ref="formRef" v-model="form" fl:layout label-width="96px">
  <User.Name />
  <User.Name layout-item:span="max" />
</FormView>

validate() / resetFields() 走 FormView 的 ref(代理内层 Form)。栅格细节见 docs/adr。

在线 Playground

GitHub Pages(仓库需在 Settings → Pages → Source 选 GitHub Actions,推 main 后生成):

本地预览打包结果:PAGES_BASE=/vue-formx/ pnpm build:pages,再用任意静态服务器打开 site/。

仓库结构

packages/vue-formless              # 内核(npm:vue-formless)
packages/layout                    # 内部栅格,打进内核 dist
playground                         # Element Plus 基线 vs Formless
playground-layout                  # 24 格布局工作台
docs/adr.md                        # 架构决策(单篇汇总)

开发

pnpm i
pnpm dev          # 启动 playground
pnpm build        # 构建库
pnpm test
pnpm typecheck

Playground 对照:基础表单、筛选条、只读详情、混合布局、DateRange。

pnpm playground
# http://localhost:5173
pnpm playground:layout
# http://localhost:5174

License

MIT