<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andreas B. Vestergaard</title>
    <description>The latest articles on DEV Community by Andreas B. Vestergaard (@aboesig).</description>
    <link>https://dev.to/aboesig</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F251033%2F805df859-c2f4-4c67-98f3-7750a826c7f5.jpg</url>
      <title>DEV Community: Andreas B. Vestergaard</title>
      <link>https://dev.to/aboesig</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aboesig"/>
    <language>en</language>
    <item>
      <title>CSS Grid vs. Position Absolute for Overlapping Elements</title>
      <dc:creator>Andreas B. Vestergaard</dc:creator>
      <pubDate>Wed, 12 Mar 2025 08:03:38 +0000</pubDate>
      <link>https://dev.to/aboesig/position-absolute-vs-css-grid-3g6m</link>
      <guid>https://dev.to/aboesig/position-absolute-vs-css-grid-3g6m</guid>
      <description>&lt;p&gt;When you need to position elements on top of each other, many developers instinctively reach for position: absolute. While this approach works, it comes with several drawbacks including elements being removed from the document flow, which can cause layout issues and complicate responsive design.&lt;/p&gt;

&lt;p&gt;CSS Grid offers a more elegant solution for creating overlapping elements. By placing multiple child elements in the same grid cell, you can achieve the same visual effect while maintaining a more predictable layout system.&lt;/p&gt;

&lt;p&gt;Here's a simple implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.parent {
  display: grid;
  grid-template-columns: 1fr;
  grid-auto-rows: min-content;
}

.div1 {
  grid-area: 1 / 1 / 2 / 2;
}

.div2 {
  grid-area: 1 / 1 / 2 / 2;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The beauty of this approach is that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All elements remain in the document flow&lt;/li&gt;
&lt;li&gt;The parent container will properly size itself based on its content&lt;/li&gt;
&lt;li&gt;It's easier to center content or align it consistently&lt;/li&gt;
&lt;li&gt;You gain all the responsive benefits of CSS Grid&lt;/li&gt;
&lt;li&gt;Z-index still works as expected to control stacking order&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This technique is particularly useful for card overlays, image captions, or any UI component where elements need to be stacked precisely.&lt;/p&gt;

&lt;p&gt;For more complex overlapping patterns, you can combine this with the z-index property to control which elements appear on top, just as you would with absolutely positioned elements.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>How to make a spacing component for Gutenberg Blocks</title>
      <dc:creator>Andreas B. Vestergaard</dc:creator>
      <pubDate>Wed, 12 Mar 2025 07:59:48 +0000</pubDate>
      <link>https://dev.to/aboesig/how-to-make-a-spacing-component-for-gutenberg-blocks-na6</link>
      <guid>https://dev.to/aboesig/how-to-make-a-spacing-component-for-gutenberg-blocks-na6</guid>
      <description>&lt;p&gt;One of the challenges we faced while building custom Gutenberg blocks was providing clients with an intuitive way to control spacing. Clients often need to adjust the spacing above or below blocks to maintain visual hierarchy and improve readability. To solve this problem, we developed a reusable SpacingSettings component.&lt;br&gt;
The Problem&lt;/p&gt;

&lt;p&gt;Before creating this component, we had to implement spacing controls for each block individually, leading to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Duplicated code across multiple blocks&lt;/li&gt;
&lt;li&gt;Inconsistent UI for spacing controls&lt;/li&gt;
&lt;li&gt;Maintenance headaches when changes were needed&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Our Solution
&lt;/h2&gt;

&lt;p&gt;We created a reusable SpacingSettings component that can be easily imported and used across all our custom blocks. This component provides toggle controls for spacing at the top and bottom of blocks.&lt;/p&gt;

&lt;p&gt;The core of our solution is a simple React component that leverages WordPress's built-in UI components. The component accepts properties for current spacing values, a change handler, and customizable labels.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const {
  element: { Fragment },
  components: { ToggleControl }
} = wp

const SpacingSettings = ({ onChange, spacingTop, spacingBottom, labels }) =&amp;gt; {
  return (
    &amp;lt;Fragment&amp;gt;
      {typeof spacingTop !== 'undefined' &amp;amp;&amp;amp; (
        &amp;lt;ToggleControl
          label={labels?.spacingTop?.label || 'Spacing Top'}
          help={spacingTop ? labels?.spacingTop?.enabled || 'Block has spacing top.' : labels?.spacingTop?.disabled || 'Block does not have spacing top.'}
          checked={spacingTop}
          onChange={(value) =&amp;gt; onChange('spacingTop', value)}
        /&amp;gt;
      )}
      {typeof spacingBottom !== 'undefined' &amp;amp;&amp;amp; (
        &amp;lt;ToggleControl
          label={labels?.spacingBottom?.label || 'Spacing Bottom'}
          help={spacingBottom ? labels?.spacingBottom?.enabled || 'Block has spacing bottom.' : labels?.spacingBottom?.disabled || 'Block does not have spacing bottom.'}
          checked={spacingBottom}
          onChange={(value) =&amp;gt; onChange('spacingBottom', value)}
        /&amp;gt;
      )}
    &amp;lt;/Fragment&amp;gt;
  )
}

export default SpacingSettings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down what this component does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It imports the necessary WordPress components (Fragment and ToggleControl)&lt;/li&gt;
&lt;li&gt;It conditionally renders spacing controls based on provided props&lt;/li&gt;
&lt;li&gt;It handles the toggling of spacing options and communicates changes back to the parent block&lt;/li&gt;
&lt;li&gt;It supports customizable labels with sensible defaults&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Use It
&lt;/h2&gt;

&lt;p&gt;Implementing the component in any block is straightforward. You simply import it and include it in your block's Inspector Controls panel.&lt;/p&gt;

&lt;p&gt;The component requires just a few props:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;spacingTop and spacingBottom: Boolean values that determine the current state&lt;/li&gt;
&lt;li&gt;onChange: A function that updates the block attributes when spacing is toggled&lt;/li&gt;
&lt;li&gt;labels: An optional object for customizing the text displayed in the UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Making It Work in the Frontend&lt;/p&gt;

&lt;p&gt;The toggle controls are only half the solution. We add CSS classes based on the toggle states to make the spacing affect the block's appearance.&lt;/p&gt;

&lt;p&gt;In our block's save function, we use the classnames utility to apply spacing classes conditionally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const blockClasses = classnames(
  'my-custom-block',
  {
    'has-spacing-top': spacingTop,
    'has-spacing-bottom': spacingBottom
  }
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in our stylesheet, we define what those spacing classes actually do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.has-spacing-top {
  margin-top: 2rem;
}

.has-spacing-bottom {
  margin-bottom: 2rem;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;This component has significantly improved our development workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DRY Code: We eliminated repetitive code across our block library&lt;/li&gt;
&lt;li&gt;Consistent UI: All blocks now have the same spacing controls&lt;/li&gt;
&lt;li&gt;Easier Maintenance: Changes to spacing controls only need to be made in one place&lt;/li&gt;
&lt;li&gt;Client Satisfaction: Clients appreciate the intuitive controls for adjusting layout spacing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Creating reusable components for common functionality is a powerful pattern in Gutenberg development. It not only makes your codebase more maintainable but also creates a more consistent experience for content editors.&lt;/p&gt;

&lt;p&gt;We've since applied this same pattern to other common block settings like background colors, animations, and responsive visibility options. Each reusable component has further streamlined our development process.&lt;/p&gt;

&lt;p&gt;By investing time in building these foundation components, we've been able to develop new blocks much faster while maintaining a consistent editing experience across our entire block library.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>gutenberg</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>How to use Native Share on iOS and Android</title>
      <dc:creator>Andreas B. Vestergaard</dc:creator>
      <pubDate>Tue, 11 Mar 2025 20:18:29 +0000</pubDate>
      <link>https://dev.to/aboesig/how-to-use-native-share-on-ios-and-android-1apo</link>
      <guid>https://dev.to/aboesig/how-to-use-native-share-on-ios-and-android-1apo</guid>
      <description>&lt;h1&gt;
  
  
  How to Use Native Share on iOS and Android
&lt;/h1&gt;

&lt;p&gt;In today's mobile-first world, creating seamless experiences for your users is crucial. One feature that can significantly enhance user experience is native sharing functionality. Rather than building custom sharing interfaces, modern web applications can leverage the Web Share API to tap into the device's built-in sharing capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Native Sharing Matters
&lt;/h2&gt;

&lt;p&gt;Native sharing provides a familiar interface for users, allowing them to share content through their preferred applications without leaving your website. This seamless experience not only improves usability but can also increase engagement and content distribution.&lt;/p&gt;

&lt;p&gt;When users encounter content they want to share, they expect a quick and intuitive process. The Web Share API delivers exactly that by presenting the same sharing sheet they're accustomed to using in native applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Web Share API
&lt;/h2&gt;

&lt;p&gt;The Web Share API is a relatively new browser feature that bridges the gap between web and native applications. It allows websites to trigger the device's native sharing dialog with just a few lines of code.&lt;/p&gt;

&lt;p&gt;At its core, the API is remarkably simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const handleShare = async ( button: HTMLElement ): Promise&amp;lt; void &amp;gt; =&amp;gt; {
    const title = document.title;
    const url = window.location.href;

    try {
      if ( navigator.share &amp;amp;&amp;amp; isMobile ) {
        await navigator.share( { title, url } );
      } else if ( navigator.clipboard ) {
        await navigator.clipboard.writeText( url );
      } else {
        throw new Error( 'Sharing is not supported in your browser.' );
      }
      updateButtonState( button, true );
    } catch ( error ) {
      console.error(
        'Error sharing:',
        error instanceof Error ? error.message : String( error )
      );
    }
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simple function call invokes the device's sharing panel, allowing users to select their preferred sharing method.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mobile Detection with window.matchMedia
&lt;/h2&gt;

&lt;p&gt;Since native sharing is primarily useful on mobile devices, it's important to detect whether the user is on a mobile device. The window.matchMedia API provides an elegant solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mediaQuery = window.matchMedia( '(max-width: 768px)' );
let isMobile = mediaQuery.matches;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach uses a media query to determine if the device's screen width is below a certain threshold (768px in this case), which is a common breakpoint for distinguishing between mobile and desktop devices.&lt;/p&gt;

&lt;p&gt;What makes this approach particularly powerful is that it responds to changes in the viewport size.&lt;/p&gt;

&lt;p&gt;With this listener in place, your application will adapt its sharing behavior if the user rotates their device or resizes their browser window.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Throttling for Better User Experience
&lt;/h2&gt;

&lt;p&gt;User interfaces should be responsive but also protected against accidental or rapid repeated actions. Throttling is a technique that limits how frequently a function can be executed, which is perfect for share buttons.&lt;/p&gt;

&lt;p&gt;A simple throttle implementation might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const throttle = &amp;lt; T extends ( ...args: unknown[] ) =&amp;gt; unknown &amp;gt;(
    func: T,
    delay: number
  ): ( ( ...args: Parameters&amp;lt; T &amp;gt; ) =&amp;gt; void ) =&amp;gt; {
    let timeoutId: ReturnType&amp;lt; typeof setTimeout &amp;gt; | null = null;

    return function ( this: unknown, ...args: Parameters&amp;lt; T &amp;gt; ): void {
      if ( ! timeoutId ) {
        func.apply( this, args );
        timeoutId = setTimeout( () =&amp;gt; {
          timeoutId = null;
        }, delay );
      }
    };
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function creates a wrapper that only allows the original function to be called once within the specified delay period. When applied to a share button, it prevents users from triggering multiple share dialogs by rapidly clicking the button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const addShareListener = ( button: HTMLElement ) =&amp;gt; {
    button.addEventListener( 'click', () =&amp;gt; throttledShare( button ) );
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Graceful Fallbacks for Unsupported Browsers
&lt;/h2&gt;

&lt;p&gt;Not all browsers support the Web Share API, particularly on desktop platforms. It's essential to provide fallbacks for these scenarios:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      if ( navigator.share &amp;amp;&amp;amp; isMobile ) {
        await navigator.share( { title, url } );
      } else if ( navigator.clipboard ) {
        await navigator.clipboard.writeText( url );
      } else {
        throw new Error( 'Sharing is not supported in your browser.' );
      }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This progressive enhancement approach ensures that all users can share content, regardless of their browser's capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visual Feedback for User Actions
&lt;/h2&gt;

&lt;p&gt;When users interact with your share button, providing visual feedback is important. This could be as simple as updating the button text temporarily.&lt;/p&gt;

&lt;p&gt;This feedback reassures users that their action was successful and completes the interaction loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Browser Compatibility Considerations
&lt;/h2&gt;

&lt;p&gt;The Web Share API has gained significant support in recent years, but it's still important to be aware of compatibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iOS Safari: Supported since version 12.2&lt;/li&gt;
&lt;li&gt;Android Chrome: Supported since version 75&lt;/li&gt;
&lt;li&gt;Android Firefox: Supported since version 79&lt;/li&gt;
&lt;li&gt;Desktop browsers: Limited support, primarily in Chromium-based browsers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By implementing proper feature detection and fallbacks, you can provide a consistent experience across all platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;A well-implemented share button combines all these elements: feature detection, mobile awareness, throttling, and user feedback. The resulting functionality feels native and intuitive, enhancing the overall user experience of your web application.&lt;/p&gt;

&lt;p&gt;When implementing sharing in your projects, remember that the goal is to create a seamless experience that feels natural to users. The Web Share API allows you to leverage the platform's native capabilities, resulting in a familiar and efficient experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Native sharing capabilities represent an important bridge between web and native applications. By implementing the Web Share API with proper mobile detection and throttling, you can provide users with a sharing experience that feels truly native to their device.&lt;/p&gt;

&lt;p&gt;As web technologies continue to evolve, we can expect even more powerful integrations between web applications and native platform features. For now, the Web Share API offers a compelling solution for one of the most common user interactions: sharing content with friends and colleagues.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>android</category>
      <category>socialmedia</category>
    </item>
    <item>
      <title>How do I know if I need Core-js as a dependency?</title>
      <dc:creator>Andreas B. Vestergaard</dc:creator>
      <pubDate>Sat, 27 Jan 2024 20:40:34 +0000</pubDate>
      <link>https://dev.to/aboesig/how-do-i-know-if-i-need-core-js-as-a-dependency-2ojo</link>
      <guid>https://dev.to/aboesig/how-do-i-know-if-i-need-core-js-as-a-dependency-2ojo</guid>
      <description>&lt;p&gt;I recently dove deep into all the different npm packages we are using on one of our projects, and I started wondering how to proper test if we really need core-js as a devDependency.&lt;/p&gt;

&lt;p&gt;I am having a hard time figuring out how to test if we need it or not - and would love to hear from you 👌&lt;/p&gt;

&lt;p&gt;Is core-js still relevant and are there good alternatives?&lt;/p&gt;

&lt;p&gt;🦄&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Use XCode Simulator for easy mobile testing</title>
      <dc:creator>Andreas B. Vestergaard</dc:creator>
      <pubDate>Mon, 06 Mar 2023 10:23:06 +0000</pubDate>
      <link>https://dev.to/aboesig/use-xcode-simulator-for-easy-mobile-testing-4icl</link>
      <guid>https://dev.to/aboesig/use-xcode-simulator-for-easy-mobile-testing-4icl</guid>
      <description>&lt;p&gt;Want to make sure your website looks good on iPhones without having an actual device? Apple's Xcode comes with a built-in simulator that makes this super easy. Here's how to use it to test your websites during development.&lt;/p&gt;

&lt;p&gt;First, you'll need to download Xcode from the Mac App Store if you haven't already. It's free but pretty big (around 10GB), so be patient during installation. Once installed, open Xcode and go to "Xcode" menu → "Open Developer Tool" → "Simulator." You don't need to create an actual Xcode project - the Simulator can run independently.&lt;/p&gt;

&lt;p&gt;When the Simulator launches, it will show a virtual iPhone on your screen. You can change which device it simulates by going to "File" → "Open Simulator" and selecting a different device like an iPad or a different iPhone model. Once your virtual device is up and running, just open Safari on it and type in your website address. You'll see exactly how your site looks and functions on that device!&lt;/p&gt;

&lt;p&gt;Want to test different orientations? Just use "Command + Left Arrow" to rotate to landscape mode or "Command + Right Arrow" to go back to portrait. You can also test gestures like pinch-to-zoom right on your Mac using your trackpad or mouse. This makes it super easy to spot any layout issues before your users do.&lt;/p&gt;

&lt;p&gt;Don't have your iPhone with you but still want to test on a real device? No problem! You can actually connect your iPhone to your Mac with a USB cable and inspect your website that way. First, make sure your iPhone and Mac are connected. Then on your iPhone, open Safari and navigate to your website. On your Mac, open Safari, go to the "Develop" menu (if you don't see it, enable it in Safari preferences under Advanced), find your iPhone's name, and select the page you want to inspect. Now you can see how your site performs on an actual device!&lt;/p&gt;

&lt;p&gt;Testing on both the simulator and real devices is super important because sometimes things look different in the real world. The simulator is great for quick tests during development, while connecting a real iPhone gives you the most accurate picture of how users will experience your site. Either way, these tools make it much easier to create websites that work perfectly on mobile without the headache of constant deployments just to check small changes.&lt;/p&gt;

</description>
      <category>xcode</category>
      <category>simulator</category>
      <category>mobile</category>
      <category>responsive</category>
    </item>
  </channel>
</rss>
