- From: CSS Meeting Bot via GitHub <noreply@w3.org>
- Date: Tue, 31 Mar 2026 17:03:11 +0000
- To: public-css-archive@w3.org
The CSS Working Group just discussed `Proposal: Declarative Web Haptics`, and agreed to the following:
* `RESOLVED: accept haptics as a work item`
* `SUMMARY: Proposal needs reworking based on points raised in the discussion, but there's interest in the topic.`
<details><summary>The full IRC log of that discussion</summary>
<TabAtkins> liminzhu: wanna talk about the new Web Haptics proposal<br>
<ydaniv> Yehonatan Daniv, Wix<br>
<TabAtkins> liminzhu: gonna go thru the explainer, and ask som eopen questions i want feedback on<br>
<TabAtkins> liminzhu: free free to ask questions<br>
<kbabbitt> explainer link: https://github.com/w3c/csswg-drafts/issues/13728<br>
<TabAtkins> liminzhu: to set the stage, folks are somewaht familiar with haptics<br>
<ChrisL> Chris Lilley, W3C<br>
<TabAtkins> liminzhu: every os has it to an extent<br>
<TabAtkins> liminzhu: scrolling thru date-time picker, docking windows, etc<br>
<TabAtkins> liminzhu: haptics adds grounding and interest to the user epxerience<br>
<TabAtkins> liminzhu: and more haptics-capable devices<br>
<TabAtkins> liminzhu: right now we only have navigator.vibrate()<br>
<TabAtkins> liminzhu: barely supported anywhere<br>
<TabAtkins> liminzhu: so not something webdevs can rely on<br>
<TabAtkins> liminzhu: it also takes a raw pattern array, as a webdev i have to handwrite the pattern<br>
<TabAtkins> liminzhu: a hassle<br>
<TabAtkins> liminzhu: it's also just JS, can't do it declaratively to get easier authoring and lower latency<br>
<TabAtkins> liminzhu: so i'm proposing a new haptics ui that's sematnics-based<br>
<TabAtkins> liminzhu: instead of expressing a pattern, you say th eintended effect. a tick, etc<br>
<TabAtkins> liminzhu: UA maps intent to what the hardware wants to express it as<br>
<TabAtkins> liminzhu: have a declarative form, css, and an imperative in JS<br>
<TabAtkins> liminzhu: covers all the places where css doesn't cover well<br>
<TabAtkins> liminzhu: gonna focus on the css side today but i'll intro the js one too<br>
<TabAtkins> liminzhu: in goals, wanna get a standard cross-platform haptics capability, low latencywithout js<br>
<TabAtkins> liminzhu: non-goal, not guarantee haptics are identical across platforms. UAs can decide the best native3 way to epxress intents<br>
<TabAtkins> liminzhu: we're also scopign to *reactive* haptics, direct response to user actions rather than long-term notification-style haptics to *gian* attention<br>
<TabAtkins> liminzhu: also not targetting specialized hardware, too complex right now<br>
<TabAtkins> liminzhu: talking thru the two parameters, an effect and an optional intensity<br>
<TabAtkins> liminzhu: effect is a predefined list of effects that the UA will map to hardware<br>
<TabAtkins> liminzhu: 'hint' is a light subtle cue<br>
<TabAtkins> liminzhu: 'edge' is a stronger boudnary signal<br>
<TabAtkins> liminzhu: 'tick' is a firm pulse like when scrolling a date-time picker<br>
<Rossen> q?<br>
<TabAtkins> liminzhu: 'align' when snapping shapes, etc<br>
<lea> q?<br>
<TabAtkins> liminzhu: crisp confirmation two things are locking together<br>
<TabAtkins> liminzhu: this table shows some guidelines for how various OSes can map the hints to existing effects<br>
<TabAtkins> liminzhu: Intensity is a 0-1 values. it compounds with system-level intensity.<br>
<TabAtkins> liminzhu: imperative API is is `navigator.playHaptics(effect, intensity)`<br>
<TabAtkins> liminzhu: note that it doesn't return a signal on whether it played or not. shoudl alleviate some fingerprinting<br>
<TabAtkins> liminzhu: and it's intended to be an optional upgrade, not something you depend on<br>
<TabAtkins> liminzhu: 'haptic-feedback' property: effect intensity?<br>
<TabAtkins> liminzhu: can do `button:active { haptic-feedback: align; }` etc<br>
<TabAtkins> liminzhu: i don't think there's any existing css mechanism where something fires for some pseudoclass changes but not all<br>
<TabAtkins> liminzhu: but for haptics it probably only makes sense to fire for user-behavior ones<br>
<emilio> q+<br>
<TabAtkins> liminzhu: not meaningful for :first-child or whatever<br>
<TabAtkins> liminzhu: i'll get to that later<br>
<TabAtkins> q+<br>
<TabAtkins> liminzhu: there's another alt form we're thinking about mapping haptics to transitions, etc<br>
<fantasai> Probably just fire it when we fire a transition...?<br>
<TabAtkins> liminzhu: so q about which appraoch<br>
<astearns> is this analogous to animations firing on pseudo-class activation?<br>
<TabAtkins> (yes)<br>
<TabAtkins> liminzhu: also, `scroll-snap-haptic: effect intensity?`<br>
<TabAtkins> liminzhu: triggers each time a snap happens<br>
<TabAtkins> liminzhu: getting a tick when scrolling past stories on insta, for example<br>
<flackr> q+<br>
<TabAtkins> liminzhu: property is on snap container, not child<br>
<TabAtkins> liminzhu: kbabbitt also told me about :snapped pseudoclass in the works<br>
<TabAtkins> liminzhu: so we might want to just use that instead, another open q<br>
<TabAtkins> liminzhu: [technical difficulties]<br>
<lea> q+<br>
<TabAtkins> emilio: the use of pseudo-classes... i'd like to get a better sense of hwo this integrates with transitions<br>
<TabAtkins> emilio: the current appraoch of, presumably when the element gets this property it triggers the feedback<br>
<TabAtkins> emilio: i think that's fine, but it raises the question - if you apply this prop to a thousand elements at once, what happens<br>
<TabAtkins> emilio: so it feels like that needs a little more fleshing out. you toggle a class, suddenly multiple elements get this property with opposing values<br>
<TabAtkins> emilio: i suppose youd' limit to what's under the pointer... but multiple coudl be there too<br>
<TabAtkins> liminzhu: [is back]<br>
<TabAtkins> liminzhu: so the q about pseudoclasses<br>
<TabAtkins> liminzhu: it's a bit of a novel appraoch<br>
<TabAtkins> liminzhu: an alternative is a transition-based haptics<br>
<TabAtkins> liminzhu: you tie the haptics to a transition<br>
<TabAtkins> liminzhu: fairly clean if you alreayd have a transition set up<br>
<TabAtkins> liminzhu: but this is also tying a haptic to a transition. if all i care about is a bit of a haptic on a button click, artificially i need to add a transition to the element. maybe not what i want<br>
<TabAtkins> liminzhu: i'm open to either doing transitions as a replacement or a future extension, both are okay<br>
<TabAtkins> liminzhu: the rest of the alternative<br>
<florian> q+<br>
<TabAtkins> Zakim: html attributes, `<button haptic-on-activate=hint>` etc. so manya ttributes tho, not really better than css approach<br>
<TabAtkins> liminzhu: haptic-on-snap, consider just using :snapped instead<br>
<TabAtkins> liminzhu: priv/sec things<br>
<TabAtkins> liminzhu: trying to avoid a new fingerprinting vector<br>
<TabAtkins> liminzhu: so no querying about device functionality<br>
<TabAtkins> liminzhu: or whether the haptic played<br>
<TabAtkins> liminzhu: for security, people have been concerned about vibrate api<br>
<TabAtkins> liminzhu: so i think UAs should be allowed in the spec to throttle as appropriate. UA-defined<br>
<TabAtkins> liminzhu: shutting down bad websites entirely, or limit how often a normal website can do it<br>
<TabAtkins> liminzhu: but also haptics aren't long-term harm. if a website vibes my mouse a lot, i can just close the site<br>
<TabAtkins> liminzhu: assume people will just avoid harassing sites<br>
<astearns> "just don’t use that site" isn’t a valid solution when sites are required (govt, etc.)<br>
<TabAtkins> liminzhu: so i'm looking for feedback on proposal, on pseudoclass, on scroll-snap-haptic vs :snapped, etc<br>
<TabAtkins> emilio: key thing to be defined is when exactly do you apply the haptic<br>
<TabAtkins> emilio: other issue with this, say you do `*:focus { haptic-feedback: ...}|` and you're tabbing the document, you probably don't want haptic since you're using the keyboard<br>
<TabAtkins> liminzhu: i think this is important, i might have buried this accidentally<br>
<TabAtkins> liminzhu: especially for imperative, only want to play haptics when the user interaction si coming from a a haptic-capable input device<br>
<TabAtkins> liminzhu: so if i'm tabbing, and my keyboard doesn't vibrate, i don't want to trigger a haptic on the mouse<br>
<TabAtkins> liminzhu: haven't given enough thought to how that applies to the css version<br>
<Rossen> ack emilio<br>
<TabAtkins> emilio: that ties into my other feedback, what if mutliple haptics happen at the same time with different values<br>
<TabAtkins> emilio: feels weird to access a global device (your haptic device) with something that can be activated from a bunch of palces independently<br>
<TabAtkins> emilio: so if document style changes in a way where two elements both get haptic feedback values, which do you take into account<br>
<TabAtkins> liminzhu: don't have a great answer yet. restating: handle the triggering device well. And when multiple haptics trigger at once, which one wins.<br>
<fantasai> scribe+<br>
<Rossen> ack florian<br>
<Rossen> ack flackr<br>
<Rossen> q+ florian<br>
<TabAtkins> flackr: i don't understand what it measn to say "this is a pseudoclass property"<br>
<TabAtkins> flackr: this is just a css property. maybe it can onlyb e set in some pseudoclasses, but that's a different detail<br>
<ydaniv> q+<br>
<TabAtkins> flackr: if someone sets a haptic from one class, and another haptic from another class, is that a haptic trigger? or is like a transition and it might not go?<br>
<TabAtkins> flackr: in the longterm people might write custom haptics, woudl be good to make sure we can do --name that hook into that<br>
<dbaron> s/might not go/might not go if the computed value stays the same/<br>
<TabAtkins> flackr: a lot of this sounds like css animations, when this property starts up we start an "animation". maybe we can lean on that. but emilio raised issues about it applying to too many elements<br>
<Rossen> ack TabAtkins<br>
<fantasai> TabAtkins: First point from flackr, about what exactly the triggering mechanism is<br>
<fantasai> TabAtkins: Is it the existing transition machinery or something else<br>
<fantasai> [flackr pointed out that if you have a haptic value on two different pseudo-classes, that won't trigger a transition so wouldn't be able to tell that there should be a change]<br>
<fantasai> TabAtkins: ...<br>
<fantasai> TabAtkins: Probably can't rely on transitions. Need something more like automatically determined animation name<br>
<fantasai> TabAtkins: So you can distinguish distinct intents and trigger those even if property is applying?<br>
<fantasai> TabAtkins: idk<br>
<Rossen> ack lea<br>
<TabAtkins> lea: first, huge +1 for the problem<br>
<TabAtkins> lea: there was recent library that used horrible hacks for this, devs were v excited<br>
<TabAtkins> lea: agree with flackr and tab about reusing animation machiner, that's closest precedent<br>
<TabAtkins> lea: i don't think transitions are a good fit, not always changing other values<br>
<fantasai> s/animation/animation-triger/<br>
<fantasai> s/triger/trigger/<br>
<TabAtkins> lea: i think it's weird matching on syntax and require authors to use a particular pseudoclass, don't have precedent for that<br>
<TabAtkins> lea: authors also might be using JS-added classes to manage their states, don't want to rule that out<br>
<TabAtkins> lea: for abuse we can rely on the sticky/throttle safeguards. authors shoudl bea ble to use what selectors they want<br>
<TabAtkins> lea: i have some minor resolutions about the keywords, seem a little arbitrary and tied to what OSes currently do. a little concerned about how they extend into the future<br>
<TabAtkins> lea: agree with flackr about custom haptics in the future. dunno if existing haptics are too different across OSes<br>
<arronei> q+<br>
<TabAtkins> lea: i'm not too worried about emilio's conflict resolution. i think we can come up with something reasonable.<br>
<TabAtkins> lea: "haptic capable" was mentioned in passing, might need an MQ to detect that<br>
<ydaniv> +1 to lea<br>
<TabAtkins> lea: haptics might not be available for all sorts of reasons beyond the device itself being incapable<br>
<ydaniv> q-<br>
<TabAtkins> lea: woudl really like haptics to work without a separate snapping pseudo<br>
<TabAtkins> q+<br>
<TabAtkins> lea: so i like the :snapped idea<br>
<ydaniv> q+<br>
<lea> https://github.com/w3ctag/design-principles/issues/448<br>
<TabAtkins> lea: i recall a TAG discussiona bout when APIs shoudl be hung on navigator<br>
<TabAtkins> lea: the consensus was generally "don't"<br>
<TabAtkins> (we don't have to stick with foolish consistency tho)<br>
<TabAtkins> lea: but current .vibrate() is on nav<br>
<flackr> q+<br>
<TabAtkins> lea: another reason to not restrict to particular pseudoclass is we keep introducing new ones<br>
<TabAtkins> lea: guaranteed to go out of sync<br>
<TabAtkins> lea: but these are all nits, big +1<br>
<TabAtkins> florian: i agree with various reasons for how this wouldn't work well as a transition effect<br>
<TabAtkins> florian: also limiting to pseudoclasses is weird, for already stated reasons. but also might want a haptic when you transition *out*<br>
<TabAtkins> florian: so leaning on more animation-like, might want to split it into an at-rule that defines an effect, conflict resolution, if it's a state you enter once (regardless of hwo many elements) or if it needs to fire each time, etc<br>
<TabAtkins> florian: this is early, agree it's worth solving<br>
<TabAtkins> flackr: need iteration on how to trigger it<br>
<TabAtkins> s/flackr/florian/<br>
<Rossen> ack flackr<br>
<Rossen> ack florian<br>
<TabAtkins> dbaron: one thought aobut triggering<br>
<Rossen> ack dbaron<br>
<Rossen> q+ flackr<br>
<TabAtkins> dbaron: a problem Lea and Rob mentioned, maybe you want to trigger more than once as an element switches between states, no way to do that if it's about a property's computed value that jus tstays the same<br>
<TabAtkins> dbaron: one thought it coudl give author a space to give a name, that name changing would be a computed-value change<br>
<florian> +1<br>
<TabAtkins> dbaron: that would probably let authors make choices about how often something triggers, what classes are same or different<br>
<TabAtkins> dbaron: maybe there are some parallels with random()...<br>
<TabAtkins> (this is what I was thinking...)<br>
<TabAtkins> dbaron: some authors might want names per-element, others not<br>
<TabAtkins> dbaron: maybe that's overboard. but occurred to me there might be a similarity there<br>
<TabAtkins> arronei: as i was looking at this, i was thi8nking it's easy for a user to say "apply this to every element", how do we scope it down<br>
<Rossen> ack arronei<br>
<TabAtkins> arronei: some ways to think about this is, MQs can help scope it down. expanding it with... not using @keyframes but using something similar.<br>
<TabAtkins> arronei: defining in vs out haptic firing, etc<br>
<TabAtkins> arronei: last thing is the vocab - hint/edge/tick/align<br>
<TabAtkins> arronei: these are similar concepts to border... something that is more in line with other properties. maybe a rename opportunity<br>
<Rossen> ack TabAtkins<br>
<fantasai> TabAtkins: I had a question, mentioned scroll snap haptic use case<br>
<fantasai> TabAtkins: scrolling through a feed and getting ticks<br>
<fantasai> liminzhu: Or scrolling through an album<br>
<lea> q?<br>
<fantasai> TabAtkins: We can't use :snapped pseudo-class for that<br>
<fantasai> TabAtkins: This is more like scroll-snap-stop<br>
<fantasai> TabAtkins: :snapped applies to the item<br>
<fantasai> flackr: We apply :snapped as we scroll through<br>
<fantasai> TabAtkins: We do? That ... seems ... strange<br>
<fantasai> TabAtkins: If that's the case then that would work<br>
<Rossen> ack ydaniv<br>
<TabAtkins> ydaniv: Lea mentioned MQs for checking whether haptics are supported<br>
<TabAtkins> ydaniv: didn't see in proposal an MQ checking for a user preference, whether they want haptics at all<br>
<florian> q+ to comment on mediaqueries<br>
<TabAtkins> `(prefers-haptics)`<br>
<Rossen> ack florian<br>
<Zakim> florian, you wanted to comment on mediaqueries<br>
<Rossen> ack flackr<br>
<Rossen> q+ florian<br>
<TabAtkins> flackr: :snapped pseudo is impl'd in Chrome, might alreayd work<br>
<TabAtkins> flackr: there's a non-interaction use-case i didn't see discussed<br>
<TabAtkins> flackr: for notification-like haptics, a vibrate when a new message is added to a chat, or mentions you...<br>
<TabAtkins> flackr: is that something we shoudl be discouraging, or supporting?<br>
<TabAtkins> flackr: so are we allowing for just interaction-based, or allowing for attention-call?<br>
<TabAtkins> liminzhu: in the explainer right now i'm scoping to interaction. attention is a lot more complexity, what haptic devices are available and what to fire on<br>
<TabAtkins> liminzhu: i think we're not ready for that in v1<br>
<TabAtkins> liminzhu: but if we see dev interest we can reconsider<br>
<Rossen> ack florian<br>
<TabAtkins> florian: the suggestion to use MQ is interesting<br>
<lea> q?<br>
<lea> q+<br>
<TabAtkins> florian: if peopel are relying on haptics as *the* mechanism, kinowing that is good<br>
<Rossen> Zakim, close queue<br>
<Zakim> ok, Rossen, the speaker queue is closed<br>
<TabAtkins> florian: but the presentation hiighlighted that on the JS side they deliberating don't give you a return value so you don't know if it worked, so there's a bit of tension<br>
<lea> qq+<br>
<TabAtkins> florian: but maybe we shouldn't encourage people to use haptics as primary. should maybe tell them to never rely on it being there, and always have some additional way to signal important things<br>
<TabAtkins> florian: but there is indeed tension betwee convenience and the fingerprinting<br>
<Rossen> ack lea<br>
<TabAtkins> lea: the arg for the MQ isn't that authors would rely on it, but it's additiaonl point of feedback<br>
<TabAtkins> lea: if the haptic isn't there they might need to provide other UI signals<br>
<TabAtkins> lea: if you know you can use haptics you can be more subtle in the UI<br>
<TabAtkins> lea: another point mentioned earlier, extending .vibrate() was mentioned as an alt<br>
<TabAtkins> lea: was rejected because it's a different signature. we could overload the signature, not insurmountable<br>
<Rossen> ack fantasai<br>
<TabAtkins> lea: might be good to reduce api surface<br>
<TabAtkins> fantasai: i think webkit ahs concerns around abuse of the api, either harassing with too much<br>
<TabAtkins> fantasai: so in addition to figuring out how it works with css, also concern with how to prevent websites causing problems for users<br>
<TabAtkins> Rossen: +1<br>
<lea> fantasai: Users are currently toggling hidden switches to emulate haptics in Safari. The fact that this is possible makes the argument a bit iffy<br>
<TabAtkins> Rossen: do we want to resolve to take this as an ED?<br>
<lea> +1 to take up as ED<br>
<TabAtkins> Rossen: so proposed resolution is to add this to the charter<br>
<TabAtkins> fantasai: want to get more feedback from my team<br>
<TabAtkins> fantasai: proposal will need some reworking. not ready for an ED right now, but happy to keep working on it<br>
<TabAtkins> florian: rossen do you mean "agree to work on it" or actually udpate the charter?<br>
<TabAtkins> Rossen: agree to work on it<br>
<astearns> +1 to agreeing to continue work on this, too soon for an ED imo<br>
<TabAtkins> florian: agree with elika that accepting a draft is a little premature, but agreeing to work on it is good<br>
<TabAtkins> liminzhu: sounds reasonable, lot of things to work on<br>
<kbabbitt> +1<br>
<TabAtkins> RESOLVED: accept haptics as a work item<br>
<TabAtkins> (we should just add a github lable for it)<br>
<liminzhu> thanks everyone!<br>
<TabAtkins> (astearns could you add one)<br>
<fantasai> SUMMARY: Proposal needs reworking based on points raised in the discussion, but there's interest in the topic.<br>
</details>
--
GitHub Notification of comment by css-meeting-bot
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/13728#issuecomment-4164100971 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Tuesday, 31 March 2026 17:03:12 UTC